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
+}