@joebigelow / wix / commits / 36b1a2ce

Create failing test for issue 6309.

Sean Hall committed Jan 1, 2021 at 14:02 UTC 36b1a2ce73b394ca3ed7490a1392320e2f401cbd
9 files changed +186 -13
src/TestData/RollbackBoundary/BundleA/BundleA.wixproj new
+15
@@ -0,0 +1,15 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <ProjectReference Include="..\PackageA\PackageA.wixproj" />
8 + <ProjectReference Include="..\PackageB\PackageB.wixproj" />
9 + <ProjectReference Include="..\PackageC\PackageC.wixproj" />
10 + <ProjectReference Include="..\PackageF\PackageF.wixproj" />
11 + </ItemGroup>
12 + <ItemGroup>
13 + <PackageReference Include="WixToolset.Bal.wixext" Version="4.0.77" />
14 + </ItemGroup>
15 +</Project>
\ No newline at end of file
src/TestData/RollbackBoundary/BundleA/BundleA.wxi new
+21
@@ -0,0 +1,21 @@
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 +<?ifndef Version?>
4 +<?define Version = 1.0.0.0?>
5 +<?endif?>
6 +
7 +<Include xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
8 + <Bundle Name="~$(var.TestGroupName) - Bundle A" Version="$(var.Version)" UpgradeCode="{E8426C86-D5E4-45FA-B09D-789DC7E5E00A}" Compressed="yes">
9 + <Log Prefix="~$(var.TestGroupName)_BundleA" />
10 +
11 + <Variable Name="TestGroupName" Value="$(var.TestGroupName)" />
12 +
13 + <BootstrapperApplication>
14 + <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" />
15 + </BootstrapperApplication>
16 +
17 + <Chain>
18 + <PackageGroupRef Id="BundlePackages" />
19 + </Chain>
20 + </Bundle>
21 +</Include>
src/TestData/RollbackBoundary/BundleA/BundleA.wxs new
+16
@@ -0,0 +1,16 @@
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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 + <?include BundleA.wxi ?>
6 + <Fragment>
7 + <PackageGroup Id="BundlePackages">
8 + <MsiPackage Id="PackageC" SourceFile="$(var.PackageC.TargetPath)" Permanent="yes" /> <!-- TODO: this is a workaround for inability to specify RollbackBoundary as first package, remove when this is fixed -->
9 + <RollbackBoundary Id="nonvital" Vital="no" />
10 + <MsiPackage Id="PackageF" SourceFile="$(var.PackageF.TargetPath)" />
11 + <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" Permanent="yes" />
12 + <RollbackBoundary />
13 + <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" Permanent="yes" />
14 + </PackageGroup>
15 + </Fragment>
16 +</Wix>
src/TestData/RollbackBoundary/PackageA/PackageA.wixproj new
+9
@@ -0,0 +1,9 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{14A06CEA-CC9E-478F-AD20-5C9624827090}</UpgradeCode>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
8 + </ItemGroup>
9 +</Project>
\ No newline at end of file
src/TestData/RollbackBoundary/PackageB/PackageB.wixproj new
+9
@@ -0,0 +1,9 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{C0B6E75E-4378-4589-B3C5-A23FFA39F59B}</UpgradeCode>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
8 + </ItemGroup>
9 +</Project>
\ No newline at end of file
src/TestData/RollbackBoundary/PackageC/PackageC.wixproj new
+9
@@ -0,0 +1,9 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{1C977E8F-4E79-4E3B-A5B1-C4B0BE774041}</UpgradeCode>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
8 + </ItemGroup>
9 +</Project>
\ No newline at end of file
src/TestData/RollbackBoundary/PackageF/PackageF.wixproj new
+12
@@ -0,0 +1,12 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{E348D377-E5E7-44B0-897E-5DC8D401BF80}</UpgradeCode>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <Compile Include="..\..\Templates\PackageFail.wxs" Link="PackageFail.wxs" />
8 + </ItemGroup>
9 + <ItemGroup>
10 + <PackageReference Include="WixToolset.Util.wixext" Version="4.0.66" />
11 + </ItemGroup>
12 +</Project>
\ No newline at end of file
src/WixToolsetTest.BurnE2E/BundleInstaller.cs
+43 -13
@@ -15,6 +15,8 @@ namespace WixToolsetTest.BurnE2E
15 {
16 public const string BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
17 public const string BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH = "BundleCachePath";
18 + public const string FULL_BURN_POLICY_REGISTRY_PATH = "SOFTWARE\\WOW6432Node\\Policies\\WiX\\Burn";
19 + public const string PACKAGE_CACHE_FOLDER_NAME = "Package Cache";
20
21 public BundleInstaller(WixTestContext testContext, string name)
22 {
@@ -28,6 +30,8 @@ namespace WixToolsetTest.BurnE2E
30
31 public string BundlePdb { get; }
32
33 + private WixBundleSymbol BundleSymbol { get; set; }
34 +
35 public string TestGroupName { get; }
36
37 public string TestName { get; }
@@ -142,37 +146,63 @@ namespace WixToolsetTest.BurnE2E
146 return logFile;
147 }
148
149 + private WixBundleSymbol GetBundleSymbol()
150 + {
151 + if (this.BundleSymbol == null)
152 + {
153 + using var wixOutput = WixOutput.Read(this.BundlePdb);
154 + var intermediate = Intermediate.Load(wixOutput);
155 + var section = intermediate.Sections.Single();
156 + this.BundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
157 + }
158 +
159 + return this.BundleSymbol;
160 + }
161 +
162 + public string GetExpectedCachedBundlePath()
163 + {
164 + var bundleSymbol = this.GetBundleSymbol();
165 +
166 + using var policyKey = Registry.LocalMachine.OpenSubKey(FULL_BURN_POLICY_REGISTRY_PATH);
167 + var redirectedCachePath = policyKey?.GetValue("PackageCache") as string;
168 + var cachePath = redirectedCachePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), PACKAGE_CACHE_FOLDER_NAME);
169 + return Path.Combine(cachePath, bundleSymbol.BundleId, Path.GetFileName(this.Bundle));
170 + }
171 +
172 public string VerifyRegisteredAndInPackageCache()
173 {
147 - using var wixOutput = WixOutput.Read(this.BundlePdb);
148 - var intermediate = Intermediate.Load(wixOutput);
149 - var section = intermediate.Sections.Single();
150 - var bundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
174 + var bundleSymbol = this.GetBundleSymbol();
175 var bundleId = bundleSymbol.BundleId;
176 var registrationKeyPath = $"{BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY}\\{bundleId}";
177
154 - using var testKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
155 - Assert.NotNull(testKey);
178 + using var registrationKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
179 + Assert.NotNull(registrationKey);
180
157 - var cachePathValue = testKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH);
181 + var cachePathValue = registrationKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH);
182 Assert.NotNull(cachePathValue);
183 var cachePath = Assert.IsType<string>(cachePathValue);
184 Assert.True(File.Exists(cachePath));
185
186 + var expectedCachePath = this.GetExpectedCachedBundlePath();
187 + Assert.Equal(expectedCachePath, cachePath, StringComparer.OrdinalIgnoreCase);
188 +
189 return cachePath;
190 }
191
192 + public void VerifyUnregisteredAndRemovedFromPackageCache()
193 + {
194 + var cachedBundlePath = this.GetExpectedCachedBundlePath();
195 + this.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
196 + }
197 +
198 public void VerifyUnregisteredAndRemovedFromPackageCache(string cachedBundlePath)
199 {
167 - using var wixOutput = WixOutput.Read(this.BundlePdb);
168 - var intermediate = Intermediate.Load(wixOutput);
169 - var section = intermediate.Sections.Single();
170 - var bundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
200 + var bundleSymbol = this.GetBundleSymbol();
201 var bundleId = bundleSymbol.BundleId;
202 var registrationKeyPath = $"{BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY}\\{bundleId}";
203
174 - using var testKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
175 - Assert.Null(testKey);
204 + using var registrationKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
205 + Assert.Null(registrationKey);
206
207 Assert.False(File.Exists(cachedBundlePath));
208 }
src/WixToolsetTest.BurnE2E/RollbackBoundaryTests.cs new
+52
@@ -0,0 +1,52 @@
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 Xunit;
8 + using Xunit.Abstractions;
9 +
10 + public class RollbackBoundaryTests : BurnE2ETests
11 + {
12 + public RollbackBoundaryTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper, "RollbackBoundary") { }
13 +
14 + /// <summary>
15 + /// Installs 1 bundle:
16 + /// chain - non-vital rollback boundary, package F, package A, vital rollback boundary, package B
17 + /// package F fails
18 + /// package A and B are permanent
19 + /// Execution is supposed to be:
20 + /// package F (fails)
21 + /// rollback to non-vital rollback boundary which ignores the error and skips over package A
22 + /// install package B
23 + /// unregister since no non-permanent packages should be installed or cached.
24 + /// </summary>
25 + [Fact]
26 + public void NonVitalRollbackBoundarySkipsToNextRollbackBoundary()
27 + {
28 + var packageA = this.CreatePackageInstaller("PackageA");
29 + var packageB = this.CreatePackageInstaller("PackageB");
30 + this.CreatePackageInstaller("PackageC");
31 + this.CreatePackageInstaller("PackageF");
32 +
33 + var bundleA = this.CreateBundleInstaller("BundleA");
34 +
35 + var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
36 + var packageBSourceCodeInstalled = packageB.GetInstalledFilePath("Package.wxs");
37 +
38 + // Source file should *not* be installed
39 + Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
40 + Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}");
41 +
42 + bundleA.Install();
43 +
44 + // No non-permanent packages should have ended up installed or cached so it should have unregistered.
45 + bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
46 +
47 + // Only PackageB source file should be installed
48 + Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled));
49 + Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Should not have found Package A payload installed at: ", packageASourceCodeInstalled));
50 + }
51 + }
52 +}