aboutsummaryrefslogtreecommitdiff
path: root/src/test/burn/WixToolsetTest.BurnE2E
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:12:34 -0700
committerRob Mensching <rob@firegiant.com>2021-05-05 11:18:35 -0700
commitd8e47230e094a506406a83eb78916abf2668b29c (patch)
tree2213ee3ed1a19fd5cd19a5914a23b7f7a57318ff /src/test/burn/WixToolsetTest.BurnE2E
parent2cbe83832cc76aa379b29665de5523e82c543acf (diff)
downloadwix-d8e47230e094a506406a83eb78916abf2668b29c.tar.gz
wix-d8e47230e094a506406a83eb78916abf2668b29c.tar.bz2
wix-d8e47230e094a506406a83eb78916abf2668b29c.zip
Move Integration into test
Diffstat (limited to 'src/test/burn/WixToolsetTest.BurnE2E')
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/BasicFunctionalityTests.cs176
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/BurnE2EFixture.cs28
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/BurnE2ETests.cs63
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/CacheTests.cs133
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs611
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs30
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs112
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs469
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/IWebServer.cs20
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/LayoutTests.cs68
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/MsiTransactionTests.cs128
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/PatchTests.cs137
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/PrereqBaTests.cs76
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/RegistrationTests.cs78
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/RollbackBoundaryTests.cs52
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/SlipstreamTests.cs353
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/TestBAController.cs187
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/UpdateBundleTests.cs245
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs36
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/WebServer/CoreOwinWebServer.cs70
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/WixToolsetTest.BurnE2E.csproj33
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/runtests.cmd2
22 files changed, 3107 insertions, 0 deletions
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.IO;
7 using Xunit;
8 using Xunit.Abstractions;
9
10 public class BasicFunctionalityTests : BurnE2ETests
11 {
12 public BasicFunctionalityTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
13
14 [Fact]
15 public void CanInstallAndUninstallSimpleBundle_x86_wixstdba()
16 {
17 var packageA = this.CreatePackageInstaller("PackageA");
18
19 var bundleA = this.CreateBundleInstaller("BundleA");
20
21 var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
22
23 // Source file should *not* be installed
24 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
25
26 bundleA.Install();
27
28 var cachedBundlePath = bundleA.VerifyRegisteredAndInPackageCache();
29
30 // Source file should be installed
31 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
32
33 bundleA.Uninstall(cachedBundlePath);
34
35 // Source file should *not* be installed
36 Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageASourceCodeInstalled));
37
38 bundleA.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
39 }
40
41 [Fact]
42 public void CanInstallAndUninstallSimpleBundle_x86_testba()
43 {
44 var packageA = this.CreatePackageInstaller("PackageA");
45
46 var bundleB = this.CreateBundleInstaller("BundleB");
47
48 var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
49
50 // Source file should *not* be installed
51 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
52
53 bundleB.Install();
54
55 var cachedBundlePath = bundleB.VerifyRegisteredAndInPackageCache();
56
57 // Source file should be installed
58 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
59
60 bundleB.Uninstall(cachedBundlePath);
61
62 // Source file should *not* be installed
63 Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageASourceCodeInstalled));
64
65 bundleB.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
66 }
67
68 [Fact]
69 public void CanInstallAndUninstallSimpleBundle_x86_dnctestba()
70 {
71 var packageA = this.CreatePackageInstaller("PackageA");
72
73 var bundleC = this.CreateBundleInstaller("BundleC");
74
75 var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
76
77 // Source file should *not* be installed
78 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
79
80 bundleC.Install();
81
82 var cachedBundlePath = bundleC.VerifyRegisteredAndInPackageCache();
83
84 // Source file should be installed
85 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
86
87 bundleC.Uninstall(cachedBundlePath);
88
89 // Source file should *not* be installed
90 Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageASourceCodeInstalled));
91
92 bundleC.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
93 }
94
95 [Fact]
96 public void CanInstallAndUninstallSimpleBundle_x64_wixstdba()
97 {
98 var packageA_x64 = this.CreatePackageInstaller("PackageA_x64");
99
100 var bundleA_x64 = this.CreateBundleInstaller("BundleA_x64");
101
102 var packageASourceCodeInstalled = packageA_x64.GetInstalledFilePath("Package.wxs");
103
104 // Source file should *not* be installed
105 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A x64 payload should not be there on test start: {packageASourceCodeInstalled}");
106
107 bundleA_x64.Install();
108
109 var cachedBundlePath = bundleA_x64.VerifyRegisteredAndInPackageCache();
110
111 // Source file should be installed
112 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A x64 payload installed at: ", packageASourceCodeInstalled));
113
114 bundleA_x64.Uninstall(cachedBundlePath);
115
116 // Source file should *not* be installed
117 Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A x64 payload should have been removed by uninstall from: ", packageASourceCodeInstalled));
118
119 bundleA_x64.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
120 }
121
122 [Fact]
123 public void CanInstallAndUninstallSimpleBundle_x64_testba()
124 {
125 var packageA_x64 = this.CreatePackageInstaller("PackageA_x64");
126
127 var bundleB_x64 = this.CreateBundleInstaller("BundleB_x64");
128
129 var packageASourceCodeInstalled = packageA_x64.GetInstalledFilePath("Package.wxs");
130
131 // Source file should *not* be installed
132 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A x64 payload should not be there on test start: {packageASourceCodeInstalled}");
133
134 bundleB_x64.Install();
135
136 var cachedBundlePath = bundleB_x64.VerifyRegisteredAndInPackageCache();
137
138 // Source file should be installed
139 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A x64 payload installed at: ", packageASourceCodeInstalled));
140
141 bundleB_x64.Uninstall(cachedBundlePath);
142
143 // Source file should *not* be installed
144 Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A x64 payload should have been removed by uninstall from: ", packageASourceCodeInstalled));
145
146 bundleB_x64.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
147 }
148
149 [Fact]
150 public void CanInstallAndUninstallSimpleBundle_x64_dnctestba()
151 {
152 var packageA_x64 = this.CreatePackageInstaller("PackageA_x64");
153
154 var bundleC_x64 = this.CreateBundleInstaller("BundleC_x64");
155
156 var packageASourceCodeInstalled = packageA_x64.GetInstalledFilePath("Package.wxs");
157
158 // Source file should *not* be installed
159 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A x64 payload should not be there on test start: {packageASourceCodeInstalled}");
160
161 bundleC_x64.Install();
162
163 var cachedBundlePath = bundleC_x64.VerifyRegisteredAndInPackageCache();
164
165 // Source file should be installed
166 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A x64 payload installed at: ", packageASourceCodeInstalled));
167
168 bundleC_x64.Uninstall(cachedBundlePath);
169
170 // Source file should *not* be installed
171 Assert.False(File.Exists(packageASourceCodeInstalled), String.Concat("Package A x64 payload should have been removed by uninstall from: ", packageASourceCodeInstalled));
172
173 bundleC_x64.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
174 }
175 }
176}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.Security.Principal;
7
8 public class BurnE2EFixture
9 {
10 const string RequiredEnvironmentVariableName = "RuntimeTestsEnabled";
11
12 public BurnE2EFixture()
13 {
14 using var identity = WindowsIdentity.GetCurrent();
15 var principal = new WindowsPrincipal(identity);
16 if (!principal.IsInRole(WindowsBuiltInRole.Administrator))
17 {
18 throw new InvalidOperationException("These tests must run elevated.");
19 }
20
21 var testsEnabledString = Environment.GetEnvironmentVariable(RequiredEnvironmentVariableName);
22 if (!bool.TryParse(testsEnabledString, out var testsEnabled) || !testsEnabled)
23 {
24 throw new InvalidOperationException($"These tests affect machine state. Set the {RequiredEnvironmentVariableName} environment variable to true to accept the consequences.");
25 }
26 }
27 }
28}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.Collections.Generic;
7 using WixTestTools;
8 using Xunit;
9 using Xunit.Abstractions;
10
11 [Collection("BurnE2E")]
12 public abstract class BurnE2ETests : WixTestBase, IDisposable
13 {
14 protected BurnE2ETests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
15
16 private Stack<IDisposable> Installers { get; } = new Stack<IDisposable>();
17
18 protected BundleInstaller CreateBundleInstaller(string name)
19 {
20 var installer = new BundleInstaller(this.TestContext, name);
21 this.Installers.Push(installer);
22 return installer;
23 }
24
25 protected PackageInstaller CreatePackageInstaller(string filename)
26 {
27 var installer = new PackageInstaller(this.TestContext, filename);
28 this.Installers.Push(installer);
29 return installer;
30 }
31
32 protected TestBAController CreateTestBAController()
33 {
34 var controller = new TestBAController(this.TestContext);
35 this.Installers.Push(controller);
36 return controller;
37 }
38
39 protected IWebServer CreateWebServer()
40 {
41 var webServer = new CoreOwinWebServer();
42 this.Installers.Push(webServer);
43 return webServer;
44 }
45
46 public void Dispose()
47 {
48 while (this.Installers.TryPop(out var installer))
49 {
50 try
51 {
52 installer.Dispose();
53 }
54 catch { }
55 }
56 }
57 }
58
59 [CollectionDefinition("BurnE2E", DisableParallelization = true)]
60 public class BurnE2ECollectionDefinition : ICollectionFixture<BurnE2EFixture>
61 {
62 }
63}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System.Collections.Generic;
6 using System.IO;
7 using WixBuildTools.TestSupport;
8 using WixTestTools;
9 using WixToolset.Mba.Core;
10 using Xunit;
11 using Xunit.Abstractions;
12
13 public class CacheTests : BurnE2ETests
14 {
15 public CacheTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
16
17 [Fact]
18 public void CanCache5GBFile()
19 {
20 var packageA = this.CreatePackageInstaller("PackageA");
21 var bundleC = this.CreateBundleInstaller("BundleC");
22
23 packageA.VerifyInstalled(false);
24
25 // Recreate the 5GB payload to avoid having to copy it to the VM to run the tests.
26 var targetFilePath = Path.Combine(this.TestContext.TestDataFolder, "fivegb.file");
27 if (!File.Exists(targetFilePath))
28 {
29 var testTool = new TestTool(Path.Combine(TestData.Get(), "win-x86", "TestExe.exe"))
30 {
31 Arguments = "/lf \"" + targetFilePath + "|5368709120\"",
32 ExpectedExitCode = 0,
33 };
34 testTool.Run(true);
35 }
36
37 bundleC.Install();
38 bundleC.VerifyRegisteredAndInPackageCache();
39
40 packageA.VerifyInstalled(true);
41 }
42
43 [Fact]
44 public void CanDownloadPayloadsFromMissingAttachedContainer()
45 {
46 var packageA = this.CreatePackageInstaller("PackageA");
47 var packageB = this.CreatePackageInstaller("PackageB");
48 var bundleA = this.CreateBundleInstaller("BundleA");
49 var testBAController = this.CreateTestBAController();
50 var webServer = this.CreateWebServer();
51
52 webServer.AddFiles(new Dictionary<string, string>
53 {
54 { "/BundleA/PackageA.msi", Path.Combine(this.TestContext.TestDataFolder, "PackageA.msi") },
55 { "/BundleA/PackageB.msi", Path.Combine(this.TestContext.TestDataFolder, "PackageB.msi") },
56 });
57 webServer.Start();
58
59 // Don't install PackageB initially so it will be installed when run from the package cache.
60 testBAController.SetPackageRequestedState("PackageB", RequestState.Absent);
61
62 packageA.VerifyInstalled(false);
63 packageB.VerifyInstalled(false);
64
65 // Manually copy bundle to separate directory, install from there, and then delete it
66 // so that when run from the package cache, it can't find the attached container.
67 using (var dfs = new DisposableFileSystem())
68 {
69 var tempDirectory = dfs.GetFolder(true);
70
71 var bundleAFileInfo = new FileInfo(bundleA.Bundle);
72 var bundleACopiedPath = Path.Combine(tempDirectory, bundleAFileInfo.Name);
73 bundleAFileInfo.CopyTo(bundleACopiedPath);
74
75 bundleA.Install(bundleACopiedPath);
76 }
77
78 var bundlePackageCachePath = bundleA.VerifyRegisteredAndInPackageCache();
79
80 packageA.VerifyInstalled(true);
81 packageB.VerifyInstalled(false);
82
83 testBAController.SetPackageRequestedState("PackageB", RequestState.Present);
84
85 bundleA.Modify(bundlePackageCachePath);
86 bundleA.VerifyRegisteredAndInPackageCache();
87
88 packageA.VerifyInstalled(true);
89 packageB.VerifyInstalled(true);
90 }
91
92 [Fact]
93 public void CanFindAttachedContainerFromRenamedBundle()
94 {
95 var packageA = this.CreatePackageInstaller("PackageA");
96 var packageB = this.CreatePackageInstaller("PackageB");
97 var bundleB = this.CreateBundleInstaller("BundleB");
98 var testBAController = this.CreateTestBAController();
99
100 // Don't install PackageB initially so it will be installed when run from the package cache.
101 testBAController.SetPackageRequestedState("PackageB", RequestState.Absent);
102
103 packageA.VerifyInstalled(false);
104 packageB.VerifyInstalled(false);
105
106 // Manually copy bundle to separate directory with new name and install from there
107 // so that when run from the package cache, it has to get the attached container from the renamed bundle.
108 using (var dfs = new DisposableFileSystem())
109 {
110 var tempDirectory = dfs.GetFolder(true);
111
112 var bundleBFileInfo = new FileInfo(bundleB.Bundle);
113 var bundleBCopiedPath = Path.Combine(tempDirectory, "RenamedBundle.exe");
114 bundleBFileInfo.CopyTo(bundleBCopiedPath);
115
116 bundleB.Install(bundleBCopiedPath);
117
118 var bundlePackageCachePath = bundleB.VerifyRegisteredAndInPackageCache();
119
120 packageA.VerifyInstalled(true);
121 packageB.VerifyInstalled(false);
122
123 testBAController.SetPackageRequestedState("PackageB", RequestState.Present);
124
125 bundleB.Modify(bundlePackageCachePath);
126 bundleB.VerifyRegisteredAndInPackageCache();
127
128 packageA.VerifyInstalled(true);
129 packageB.VerifyInstalled(true);
130 }
131 }
132 }
133}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using WixTestTools;
7 using WixToolset.Mba.Core;
8 using Xunit;
9 using Xunit.Abstractions;
10
11 public class DependencyTests : BurnE2ETests
12 {
13 public DependencyTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
14
15 [Fact]
16 public void CanKeepSameExactPackageAfterUpgradingBundle()
17 {
18 var packageF = this.CreatePackageInstaller("PackageF");
19 var bundleKv1 = this.CreateBundleInstaller("BundleKv1");
20 var bundleKv2 = this.CreateBundleInstaller("BundleKv2");
21
22 packageF.VerifyInstalled(false);
23
24 bundleKv1.Install();
25 bundleKv1.VerifyRegisteredAndInPackageCache();
26
27 packageF.VerifyInstalled(true);
28
29 bundleKv2.Install();
30 bundleKv2.VerifyRegisteredAndInPackageCache();
31 bundleKv1.VerifyUnregisteredAndRemovedFromPackageCache();
32
33 packageF.VerifyInstalled(true);
34
35 bundleKv2.VerifyPackageIsCached("PackageF");
36
37 bundleKv2.Uninstall();
38 bundleKv2.VerifyUnregisteredAndRemovedFromPackageCache();
39
40 packageF.VerifyInstalled(false);
41 }
42
43 [Fact (Skip = "https://github.com/wixtoolset/issues/issues/6387")]
44 public void CanKeepSameExactPackageAfterUpgradingBundleWithSlipstreamedPatch()
45 {
46 var originalVersion = "1.0.0.0";
47 var patchedVersion = "1.0.1.0";
48 var testRegistryValue = "PackageA";
49 var testRegistryValueExe = "ExeA";
50
51 var packageA = this.CreatePackageInstaller("PackageAv1");
52 var bundleA = this.CreateBundleInstaller("BundleAv1");
53 var bundleC = this.CreateBundleInstaller("BundleC");
54
55 packageA.VerifyInstalled(false);
56
57 bundleA.Install();
58 bundleA.VerifyRegisteredAndInPackageCache();
59
60 packageA.VerifyInstalled(true);
61 packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion);
62 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, originalVersion);
63
64 // Verify https://github.com/wixtoolset/issues/issues/3294 - Uninstalling bundle registers a dependency on a package
65 bundleC.Install();
66 bundleC.VerifyRegisteredAndInPackageCache();
67 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
68
69 packageA.VerifyInstalled(true);
70 packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion);
71 bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe);
72
73 // Verify https://github.com/wixtoolset/issues/issues/2915 - Update bundle removes previously cached MSIs
74 bundleC.Repair();
75
76 bundleC.Uninstall();
77 bundleC.VerifyUnregisteredAndRemovedFromPackageCache();
78
79 packageA.VerifyInstalled(false);
80 }
81
82 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/exea")]
83 public void CanKeepUpgradedPackageAfterUninstallUpgradedBundle()
84 {
85 var testRegistryValueExe = "ExeA";
86
87 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
88 var packageAv101 = this.CreatePackageInstaller("PackageAv1_0_1");
89 var packageB = this.CreatePackageInstaller("PackageB");
90 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
91 var bundleAv101 = this.CreateBundleInstaller("BundleAv1_0_1");
92 var bundleB = this.CreateBundleInstaller("BundleB");
93
94 packageAv1.VerifyInstalledWithVersion(false);
95 packageAv101.VerifyInstalledWithVersion(false);
96 packageB.VerifyInstalled(false);
97
98 bundleAv1.Install();
99 bundleAv1.VerifyRegisteredAndInPackageCache();
100
101 packageAv1.VerifyInstalledWithVersion(true);
102 bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
103
104 bundleB.Install();
105 bundleB.VerifyRegisteredAndInPackageCache();
106
107 packageAv1.VerifyInstalledWithVersion(true);
108 bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
109 packageB.VerifyInstalled(true);
110
111 bundleAv101.Install();
112 bundleAv101.VerifyRegisteredAndInPackageCache();
113 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
114
115 packageAv1.VerifyInstalledWithVersion(false);
116 packageAv101.VerifyInstalledWithVersion(true);
117 bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.1.0");
118
119 bundleAv101.Uninstall();
120 bundleAv101.VerifyUnregisteredAndRemovedFromPackageCache();
121
122 packageAv101.VerifyInstalledWithVersion(true);
123 bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.1.0");
124 }
125
126#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES
127 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6387")]
128#else
129 [Fact(Skip = "addon/patch related bundle")]
130#endif
131 public void CanMinorUpgradeDependencyPackageFromPatchBundle()
132 {
133 var originalVersion = "1.0.0.0";
134 var patchedVersion = "1.0.1.0";
135 var testRegistryValue = "PackageA";
136
137 var packageA = this.CreatePackageInstaller("PackageAv1");
138 var packageBv1 = this.CreatePackageInstaller("PackageBv1");
139 var packageBv101 = this.CreatePackageInstaller("PackageBv1_0_1");
140 var bundleJ = this.CreateBundleInstaller("BundleJ");
141 var bundleJ_Patch = this.CreateBundleInstaller("BundleJ_Patch");
142
143 packageA.VerifyInstalled(false);
144 packageBv1.VerifyInstalled(false);
145 packageBv101.VerifyInstalled(false);
146
147 bundleJ.Install();
148 bundleJ.VerifyRegisteredAndInPackageCache();
149
150 packageA.VerifyInstalled(true);
151 packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion);
152 packageBv1.VerifyInstalled(true);
153
154 bundleJ_Patch.Install();
155 bundleJ_Patch.VerifyRegisteredAndInPackageCache();
156
157 packageA.VerifyInstalled(true);
158 packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion);
159 packageBv1.VerifyInstalled(false);
160 packageBv101.VerifyInstalled(true);
161
162 bundleJ.Uninstall();
163 bundleJ.VerifyUnregisteredAndRemovedFromPackageCache();
164 bundleJ_Patch.VerifyUnregisteredAndRemovedFromPackageCache();
165
166 packageA.VerifyInstalled(false);
167 packageBv1.VerifyInstalled(false);
168 packageBv101.VerifyInstalled(false);
169 }
170
171#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES
172 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6387")]
173#else
174 [Fact(Skip = "addon/patch related bundle")]
175#endif
176 public void CanMinorUpgradeDependencyPackageFromPatchBundleThenUninstallToRestoreBase()
177 {
178 var originalVersion = "1.0.0.0";
179 var patchedVersion = "1.0.1.0";
180 var testRegistryValue = "PackageA";
181
182 var packageA = this.CreatePackageInstaller("PackageAv1");
183 var packageBv1 = this.CreatePackageInstaller("PackageBv1");
184 var packageBv101 = this.CreatePackageInstaller("PackageBv1_0_1");
185 var bundleJ = this.CreateBundleInstaller("BundleJ");
186 var bundleJ_Patch = this.CreateBundleInstaller("BundleJ_Patch");
187
188 packageA.VerifyInstalled(false);
189 packageBv1.VerifyInstalled(false);
190 packageBv101.VerifyInstalled(false);
191
192 bundleJ.Install();
193 bundleJ.VerifyRegisteredAndInPackageCache();
194
195 packageA.VerifyInstalled(true);
196 packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion);
197 packageBv1.VerifyInstalled(true);
198
199 bundleJ_Patch.Install();
200 bundleJ_Patch.VerifyRegisteredAndInPackageCache();
201
202 packageA.VerifyInstalled(true);
203 packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion);
204 packageBv1.VerifyInstalled(false);
205 packageBv101.VerifyInstalled(true);
206
207 bundleJ_Patch.Uninstall();
208 bundleJ_Patch.VerifyUnregisteredAndRemovedFromPackageCache();
209
210 packageA.VerifyInstalled(true);
211 packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion);
212 packageBv1.VerifyInstalled(true);
213 packageBv101.VerifyInstalled(false);
214
215 bundleJ.Uninstall();
216 bundleJ.VerifyUnregisteredAndRemovedFromPackageCache();
217
218 packageA.VerifyInstalled(false);
219 packageBv1.VerifyInstalled(false);
220 packageBv101.VerifyInstalled(false);
221 }
222
223#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES
224 [Fact]
225#else
226 [Fact(Skip = "addon/patch related bundle")]
227#endif
228 public void CanUninstallBaseWithAddOnsWhenAllSharePackages()
229 {
230 var testRegistryValueExe = "ExeA";
231
232 var packageA = this.CreatePackageInstaller("PackageAv1");
233 var packageB = this.CreatePackageInstaller("PackageB");
234 var bundleF = this.CreateBundleInstaller("BundleF");
235 var bundleF_AddOnA = this.CreateBundleInstaller("BundleF_AddOnA");
236 var bundleF_AddOnB = this.CreateBundleInstaller("BundleF_AddOnB");
237
238 packageA.VerifyInstalled(false);
239 packageB.VerifyInstalled(false);
240
241 bundleF.Install();
242 bundleF.VerifyRegisteredAndInPackageCache();
243
244 packageA.VerifyInstalled(true);
245 packageB.VerifyInstalled(true);
246
247 bundleF_AddOnA.Install();
248 bundleF_AddOnA.VerifyRegisteredAndInPackageCache();
249
250 packageA.VerifyInstalled(true);
251 bundleF.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
252 packageB.VerifyInstalled(true);
253
254 bundleF_AddOnB.Install();
255 bundleF_AddOnB.VerifyRegisteredAndInPackageCache();
256
257 packageA.VerifyInstalled(true);
258 bundleF.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
259 packageB.VerifyInstalled(true);
260
261 bundleF.Uninstall();
262 bundleF.VerifyUnregisteredAndRemovedFromPackageCache();
263 bundleF_AddOnA.VerifyUnregisteredAndRemovedFromPackageCache();
264 bundleF_AddOnB.VerifyUnregisteredAndRemovedFromPackageCache();
265
266 packageA.VerifyInstalled(false);
267 bundleF.VerifyExeTestRegistryRootDeleted(testRegistryValueExe);
268 packageB.VerifyInstalled(false);
269 }
270
271 [Fact]
272 public void CanUninstallDependencyPackagesWithBundlesUninstalledInFifoOrder()
273 {
274 var testRegistryValueExe = "ExeA";
275
276 var packageA = this.CreatePackageInstaller("PackageAv1");
277 var packageB = this.CreatePackageInstaller("PackageB");
278 var bundleA = this.CreateBundleInstaller("BundleAv1");
279 var bundleB = this.CreateBundleInstaller("BundleB");
280
281 packageA.VerifyInstalled(false);
282 packageB.VerifyInstalled(false);
283
284 bundleA.Install();
285 bundleA.VerifyRegisteredAndInPackageCache();
286
287 packageA.VerifyInstalled(true);
288 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
289
290 bundleB.Install();
291 bundleB.VerifyRegisteredAndInPackageCache();
292
293 packageA.VerifyInstalled(true);
294 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
295 packageB.VerifyInstalled(true);
296
297 bundleA.Uninstall();
298 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
299
300 packageA.VerifyInstalled(true);
301 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
302 packageB.VerifyInstalled(true);
303
304 bundleB.Uninstall();
305 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
306
307 packageA.VerifyInstalled(false);
308 bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe);
309 packageB.VerifyInstalled(false);
310 }
311
312 [Fact]
313 public void CanUninstallDependencyPackagesWithBundlesUninstalledInReverseOrder()
314 {
315 var packageA = this.CreatePackageInstaller("PackageAv1");
316 var packageB = this.CreatePackageInstaller("PackageB");
317 var bundleA = this.CreateBundleInstaller("BundleAv1");
318 var bundleB = this.CreateBundleInstaller("BundleB");
319
320 packageA.VerifyInstalled(false);
321 packageB.VerifyInstalled(false);
322
323 bundleA.Install();
324 bundleA.VerifyRegisteredAndInPackageCache();
325
326 packageA.VerifyInstalled(true);
327
328 bundleB.Install();
329 bundleB.VerifyRegisteredAndInPackageCache();
330
331 packageA.VerifyInstalled(true);
332 packageB.VerifyInstalled(true);
333
334 bundleB.Uninstall();
335 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
336
337 packageA.VerifyInstalled(true);
338
339 bundleA.Uninstall();
340 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
341
342 packageA.VerifyInstalled(false);
343 packageB.VerifyInstalled(false);
344 }
345
346#if SUPPORT_ADDON_AND_PATCH_RELATED_BUNDLES
347 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6387")]
348#else
349 [Fact(Skip = "addon/patch related bundle")]
350#endif
351 public void CanUpgradePatchBundleWithAdditionalPatch()
352 {
353 var originalVersion = "1.0.0.0";
354 var patchedVersion = "1.0.1.0";
355 var patchedVersion2 = "1.0.2.0";
356 var testRegistryValue = "PackageA";
357
358 var packageA = this.CreatePackageInstaller("PackageAv1");
359 var packageB = this.CreatePackageInstaller("PackageBv1");
360 var bundleF = this.CreateBundleInstaller("BundleJ");
361 var bundleF_PatchAv101 = this.CreateBundleInstaller("BundleF_PatchAv1_0_1");
362 var bundleF_PatchAv102 = this.CreateBundleInstaller("BundleF_PatchAv1_0_2");
363
364 packageA.VerifyInstalled(false);
365 packageB.VerifyInstalled(false);
366
367 bundleF.Install();
368 bundleF.VerifyRegisteredAndInPackageCache();
369
370 packageA.VerifyInstalled(true);
371 packageA.VerifyTestRegistryValue(testRegistryValue, originalVersion);
372 packageB.VerifyInstalled(true);
373
374 bundleF_PatchAv101.Install();
375 bundleF_PatchAv101.VerifyRegisteredAndInPackageCache();
376
377 packageA.VerifyInstalled(true);
378 packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion);
379 packageB.VerifyInstalled(false);
380
381 bundleF_PatchAv102.Install();
382 bundleF_PatchAv102.VerifyRegisteredAndInPackageCache();
383
384 packageA.VerifyInstalled(true);
385 packageA.VerifyTestRegistryValue(testRegistryValue, patchedVersion2);
386 packageB.VerifyInstalled(false);
387
388 bundleF.Uninstall();
389 bundleF.VerifyUnregisteredAndRemovedFromPackageCache();
390 bundleF_PatchAv101.VerifyUnregisteredAndRemovedFromPackageCache();
391 bundleF_PatchAv102.VerifyUnregisteredAndRemovedFromPackageCache();
392
393 packageA.VerifyInstalled(false);
394 packageB.VerifyInstalled(false);
395 }
396
397 [Fact]
398 public void DoesntRegisterDependencyOnPackageNotSelectedForInstall()
399 {
400 var testRegistryValueExe = "ExeA";
401
402 var packageA = this.CreatePackageInstaller("PackageAv1");
403 var packageB = this.CreatePackageInstaller("PackageB");
404 var bundleA = this.CreateBundleInstaller("BundleAv1");
405 var bundleB = this.CreateBundleInstaller("BundleB");
406 var testBAController = this.CreateTestBAController();
407
408 packageA.VerifyInstalled(false);
409 packageB.VerifyInstalled(false);
410
411 bundleA.Install();
412 bundleA.VerifyRegisteredAndInPackageCache();
413
414 packageA.VerifyInstalled(true);
415 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
416
417 // Verify https://github.com/wixtoolset/issues/issues/3456 - Dependency registered on package though unselected to instal
418 testBAController.SetPackageRequestedState("PackageA", RequestState.None);
419 testBAController.SetPackageRequestedState("PackageB", RequestState.None);
420
421 bundleB.Install();
422 bundleB.VerifyRegisteredAndInPackageCache();
423
424 packageA.VerifyInstalled(true);
425 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
426 packageB.VerifyInstalled(false);
427
428 testBAController.ResetPackageStates("PackageA");
429 testBAController.ResetPackageStates("PackageB");
430
431 bundleA.Uninstall();
432 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
433
434 packageA.VerifyInstalled(false);
435 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
436 packageB.VerifyInstalled(false);
437
438 bundleB.Uninstall();
439 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
440
441 packageA.VerifyInstalled(false);
442 bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe);
443 packageB.VerifyInstalled(false);
444 }
445
446 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/3516")]
447 public void DoesntRollbackPackageInstallIfPreexistingDependents()
448 {
449 var packageA = this.CreatePackageInstaller("PackageAv1");
450 var packageC = this.CreatePackageInstaller("PackageC");
451 var bundleE = this.CreateBundleInstaller("BundleE");
452 var bundleL = this.CreateBundleInstaller("BundleL");
453 var testBAController = this.CreateTestBAController();
454
455 packageA.VerifyInstalled(false);
456 packageC.VerifyInstalled(false);
457
458 // Make PackageC fail.
459 testBAController.SetPackageCancelExecuteAtProgress("PackageC", 10);
460
461 bundleE.Install();
462 bundleE.VerifyRegisteredAndInPackageCache();
463
464 packageA.VerifyInstalled(true);
465 packageC.VerifyInstalled(false);
466
467 // Make PackageC install then rollback.
468 testBAController.SetPackageCancelExecuteAtProgress("PackageC", null);
469 testBAController.SetPackageCancelOnProgressAtProgress("PackageC", 10);
470
471 bundleL.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
472 bundleL.VerifyUnregisteredAndRemovedFromPackageCache();
473
474 packageA.VerifyInstalled(true);
475 packageC.VerifyInstalled(true);
476
477 testBAController.SetPackageCancelOnProgressAtProgress("PackageC", null);
478
479 bundleE.Uninstall();
480 bundleE.VerifyUnregisteredAndRemovedFromPackageCache();
481
482 packageA.VerifyInstalled(false);
483 packageC.VerifyInstalled(false);
484 }
485
486 [Fact]
487 public void RegistersDependencyOnFailedNonVitalPackages()
488 {
489 var packageA = this.CreatePackageInstaller("PackageAv1");
490 var packageC = this.CreatePackageInstaller("PackageC");
491 var bundleE = this.CreateBundleInstaller("BundleE");
492 var bundleL = this.CreateBundleInstaller("BundleL");
493 var testBAController = this.CreateTestBAController();
494
495 packageA.VerifyInstalled(false);
496 packageC.VerifyInstalled(false);
497
498 // Make PackageC fail.
499 testBAController.SetPackageCancelExecuteAtProgress("PackageC", 10);
500
501 // Verify https://github.com/wixtoolset/issues/issues/3406 - Non-vital failure result in bundle failure (install)
502 bundleE.Install();
503 bundleE.VerifyRegisteredAndInPackageCache();
504
505 packageA.VerifyInstalled(true);
506 packageC.VerifyInstalled(false);
507
508 // Verify https://github.com/wixtoolset/issues/issues/3406 - Non-vital failure result in bundle failure (repair)
509 bundleE.Repair();
510 bundleE.VerifyRegisteredAndInPackageCache();
511
512 packageA.VerifyInstalled(true);
513 packageC.VerifyInstalled(false);
514
515 testBAController.SetPackageCancelExecuteAtProgress("PackageC", null);
516
517 bundleL.Install();
518 bundleL.VerifyRegisteredAndInPackageCache();
519
520 packageA.VerifyInstalled(true);
521 packageC.VerifyInstalled(true);
522
523 // Verify https://github.com/wixtoolset/issues/issues/3516 - Burn registers dependency on failed packages
524 bundleL.Uninstall();
525 bundleL.VerifyUnregisteredAndRemovedFromPackageCache();
526
527 packageA.VerifyInstalled(true);
528 packageC.VerifyInstalled(true);
529
530 bundleE.Uninstall();
531 bundleE.VerifyUnregisteredAndRemovedFromPackageCache();
532
533 packageA.VerifyInstalled(false);
534 packageC.VerifyInstalled(false);
535 }
536
537 [Fact]
538 public void RemovesDependencyDuringUpgradeRollback()
539 {
540 var testRegistryValueExe = "ExeA";
541
542 var packageA = this.CreatePackageInstaller("PackageAv1");
543 var bundleA = this.CreateBundleInstaller("BundleAv1");
544 var bundleD = this.CreateBundleInstaller("BundleD");
545
546 packageA.VerifyInstalled(false);
547 bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe);
548
549 bundleA.Install();
550 bundleA.VerifyRegisteredAndInPackageCache();
551
552 packageA.VerifyInstalled(true);
553 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
554
555 // Verify https://github.com/wixtoolset/issues/issues/3341 - pkg dependecy not removed in rollback if pkg already present
556 bundleD.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE);
557 bundleD.VerifyUnregisteredAndRemovedFromPackageCache();
558
559 packageA.VerifyInstalled(true);
560 bundleA.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
561
562 bundleA.Uninstall();
563 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
564
565 packageA.VerifyInstalled(false);
566 bundleA.VerifyExeTestRegistryRootDeleted(testRegistryValueExe);
567 }
568
569 [Fact]
570 public void SkipsCrossScopeDependencyRegistration()
571 {
572 var packageA = this.CreatePackageInstaller("PackageAv1");
573 var packageDv1 = this.CreatePackageInstaller("PackageDv1");
574 var packageDv2 = this.CreatePackageInstaller("PackageDv2");
575 var bundleHv1 = this.CreateBundleInstaller("BundleHv1");
576 var bundleHv2 = this.CreateBundleInstaller("BundleHv2");
577
578 packageA.VerifyInstalled(false);
579 packageDv1.VerifyInstalled(false);
580 packageDv2.VerifyInstalled(false);
581
582 var bundleHv1InstallLogFilePath = bundleHv1.Install();
583 bundleHv1.VerifyRegisteredAndInPackageCache();
584
585 packageA.VerifyInstalled(true);
586 packageDv1.VerifyInstalled(true);
587
588 Assert.True(LogVerifier.MessageInLogFileRegex(bundleHv1InstallLogFilePath, @"Skipping cross-scope dependency registration on package: PackageA, bundle scope: PerUser, package scope: PerMachine"));
589
590 var bundleHv2InstallLogFilePath = bundleHv2.Install();
591 bundleHv2.VerifyRegisteredAndInPackageCache();
592 bundleHv1.VerifyUnregisteredAndRemovedFromPackageCache();
593
594 packageA.VerifyInstalled(true);
595 packageDv1.VerifyInstalled(false);
596 packageDv2.VerifyInstalled(true);
597
598 Assert.True(LogVerifier.MessageInLogFileRegex(bundleHv2InstallLogFilePath, @"Skipping cross-scope dependency registration on package: PackageA, bundle scope: PerUser, package scope: PerMachine"));
599 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"));
600
601 bundleHv2.Uninstall();
602 bundleHv2.VerifyUnregisteredAndRemovedFromPackageCache();
603
604 // Verify that permanent packageA is still installed and then remove.
605 packageA.VerifyInstalled(true);
606 packageDv2.VerifyInstalled(false);
607 packageA.UninstallProduct();
608 packageA.VerifyInstalled(false);
609 }
610 }
611}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using Xunit;
6 using Xunit.Abstractions;
7
8 public class ElevationTests : BurnE2ETests
9 {
10 public ElevationTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
11
12 /// <summary>
13 /// This test calls Elevate after Detect, and then calls Plan in OnElevateBegin.
14 /// After calling Plan, it pumps some messages to simulate UI like the UAC callback.
15 /// </summary>
16 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6349")] // CAUTION: this test currently hangs because the Plan request gets dropped.
17 public void CanExplicitlyElevateAndPlanFromOnElevateBegin()
18 {
19 var packageA = this.CreatePackageInstaller("PackageA");
20 var bundleA = this.CreateBundleInstaller("BundleA");
21 var testBAController = this.CreateTestBAController();
22
23 testBAController.SetExplicitlyElevateAndPlanFromOnElevateBegin();
24
25 bundleA.Install();
26 bundleA.VerifyRegisteredAndInPackageCache();
27 packageA.VerifyInstalled(true);
28 }
29 }
30}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using WixTestTools;
6 using Xunit;
7 using Xunit.Abstractions;
8
9 public class FailureTests : BurnE2ETests
10 {
11 public FailureTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
12
13 [Fact]
14 public void CanCancelMsiPackageVeryEarly()
15 {
16 var packageA = this.CreatePackageInstaller("PackageA");
17 var packageB = this.CreatePackageInstaller("PackageB");
18 var bundleA = this.CreateBundleInstaller("BundleA");
19 var testBAController = this.CreateTestBAController();
20
21 // Cancel package B right away.
22 testBAController.SetPackageCancelExecuteAtProgress("PackageB", 1);
23
24 bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
25 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
26
27 packageA.VerifyInstalled(false);
28 packageB.VerifyInstalled(false);
29 }
30
31 [Fact]
32 public void CanCancelMsiPackageVeryLate()
33 {
34 var packageA = this.CreatePackageInstaller("PackageA");
35 var packageB = this.CreatePackageInstaller("PackageB");
36 var bundleA = this.CreateBundleInstaller("BundleA");
37 var testBAController = this.CreateTestBAController();
38
39 // Cancel package B at the last moment possible.
40 testBAController.SetPackageCancelExecuteAtProgress("PackageB", 100);
41
42 bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
43 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
44
45 packageA.VerifyInstalled(false);
46 packageB.VerifyInstalled(false);
47 }
48
49 [Fact]
50 public void CanCancelMsiPackageInOnProgress()
51 {
52 var packageA = this.CreatePackageInstaller("PackageA");
53 var packageB = this.CreatePackageInstaller("PackageB");
54 var bundleA = this.CreateBundleInstaller("BundleA");
55 var testBAController = this.CreateTestBAController();
56
57 // Cancel package B during its OnProgress message.
58 testBAController.SetPackageCancelOnProgressAtProgress("PackageB", 100);
59
60 bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
61 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
62
63 packageA.VerifyInstalled(false);
64 packageB.VerifyInstalled(false);
65 }
66
67 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/5750")]
68 public void CanCancelExecuteWhileCaching()
69 {
70 var packageA = this.CreatePackageInstaller("PackageA");
71 var packageB = this.CreatePackageInstaller("PackageB");
72 var bundleB = this.CreateBundleInstaller("BundleB");
73 var testBAController = this.CreateTestBAController();
74
75 // Slow the caching of package B to ensure that package A starts installing and cancels.
76 testBAController.SetPackageCancelExecuteAtProgress("PackageA", 50);
77 testBAController.SetPackageSlowCache("PackageB", 2000);
78
79 bundleB.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
80 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
81
82 packageA.VerifyInstalled(false);
83 packageB.VerifyInstalled(false);
84 }
85
86 /// <summary>
87 /// BundleC has non-vital PackageA and vital PackageB.
88 /// 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.
89 /// BundleC should be able to install successfully by ignoring the missing PackageA and installing PackageB.
90 /// </summary>
91 [Fact]
92 public void CanInstallWhenMissingNonVitalPackage()
93 {
94 var packageA = this.CreatePackageInstaller("PackageA");
95 var packageB = this.CreatePackageInstaller("PackageB");
96 var bundleC = this.CreateBundleInstaller("BundleC");
97
98 var bundleCInstallLogFilePath = bundleC.Install();
99 bundleC.VerifyRegisteredAndInPackageCache();
100 Assert.True(LogVerifier.MessageInLogFileRegex(bundleCInstallLogFilePath, "Skipping apply of package: PackageA due to cache error: 0x80070002. Continuing..."));
101
102 packageA.VerifyInstalled(false);
103 packageB.VerifyInstalled(true);
104
105 bundleC.Uninstall();
106 bundleC.VerifyUnregisteredAndRemovedFromPackageCache();
107
108 packageA.VerifyInstalled(false);
109 packageB.VerifyInstalled(false);
110 }
111 }
112}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.IO;
7 using WixTestTools;
8 using Xunit;
9 using Xunit.Abstractions;
10
11 public class ForwardCompatibleBundleTests : BurnE2ETests
12 {
13 public ForwardCompatibleBundleTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
14
15 private const string BundleAProviderId = "~" + nameof(ForwardCompatibleBundleTests) + "_BundleA";
16 private const string BundleCProviderId = "~" + nameof(ForwardCompatibleBundleTests) + "_BundleC";
17 private const string V100 = "1.0.0.0";
18 private const string V200 = "2.0.0.0";
19
20 [Fact]
21 public void CanTrack1ForwardCompatibleDependentThroughMajorUpgrade()
22 {
23 string providerId = BundleAProviderId;
24 string parent = "~BundleAv1";
25 string parentSwitch = String.Concat("-parent ", parent);
26
27 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
28 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
29 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
30 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
31
32 packageAv1.VerifyInstalled(false);
33 packageAv2.VerifyInstalled(false);
34
35 // Install the v1 bundle with a parent.
36 bundleAv1.Install(arguments: parentSwitch);
37 bundleAv1.VerifyRegisteredAndInPackageCache();
38
39 packageAv1.VerifyInstalled(true);
40 packageAv2.VerifyInstalled(false);
41 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion));
42 Assert.Equal(V100, actualProviderVersion);
43 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
44
45 // Upgrade with the v2 bundle.
46 bundleAv2.Install();
47 bundleAv2.VerifyRegisteredAndInPackageCache();
48 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
49
50 packageAv1.VerifyInstalled(false);
51 packageAv2.VerifyInstalled(true);
52 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
53 Assert.Equal(V200, actualProviderVersion);
54 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
55
56 // Uninstall the v2 bundle and nothing should happen because there is still a parent.
57 bundleAv2.Uninstall();
58 bundleAv2.VerifyRegisteredAndInPackageCache();
59
60 packageAv1.VerifyInstalled(false);
61 packageAv2.VerifyInstalled(true);
62 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
63 Assert.Equal(V200, actualProviderVersion);
64 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
65
66 // Uninstall the v1 bundle with passthrough and all should be removed.
67 bundleAv1.Uninstall(arguments: parentSwitch);
68 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
69 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
70
71 packageAv1.VerifyInstalled(false);
72 packageAv2.VerifyInstalled(false);
73 Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
74 }
75
76 [Fact]
77 public void CanTrack1ForwardCompatibleDependentThroughMajorUpgradeWithParentNone()
78 {
79 string providerId = BundleAProviderId;
80 string parent = "~BundleAv1";
81 string parentSwitch = String.Concat("-parent ", parent);
82
83 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
84 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
85 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
86 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
87
88 packageAv1.VerifyInstalled(false);
89 packageAv2.VerifyInstalled(false);
90
91 // Install the v1 bundle with a parent.
92 bundleAv1.Install(arguments: parentSwitch);
93 bundleAv1.VerifyRegisteredAndInPackageCache();
94
95 packageAv1.VerifyInstalled(true);
96 packageAv2.VerifyInstalled(false);
97 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion));
98 Assert.Equal(V100, actualProviderVersion);
99 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
100
101 // Upgrade with the v2 bundle but prevent self parent being registered.
102 bundleAv2.Install(arguments: "-parent:none");
103 bundleAv2.VerifyRegisteredAndInPackageCache();
104 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
105
106 packageAv1.VerifyInstalled(false);
107 packageAv2.VerifyInstalled(true);
108 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
109 Assert.Equal(V200, actualProviderVersion);
110 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
111
112 // Uninstall the v1 bundle with passthrough and all should be removed.
113 bundleAv1.Uninstall(arguments: parentSwitch);
114 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
115 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
116
117 packageAv1.VerifyInstalled(false);
118 packageAv2.VerifyInstalled(false);
119 Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
120 }
121
122 [Fact]
123 public void CanTrack2ForwardCompatibleDependentsThroughMajorUpgrade()
124 {
125 string providerId = BundleAProviderId;
126 string parent = "~BundleAv1";
127 string parent2 = "~BundleAv1_Parent2";
128 string parentSwitch = String.Concat("-parent ", parent);
129 string parent2Switch = String.Concat("-parent ", parent2);
130
131 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
132 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
133 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
134 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
135
136 packageAv1.VerifyInstalled(false);
137 packageAv2.VerifyInstalled(false);
138
139 // Install the v1 bundle with a parent.
140 bundleAv1.Install(arguments: parentSwitch);
141 bundleAv1.VerifyRegisteredAndInPackageCache();
142
143 packageAv1.VerifyInstalled(true);
144 packageAv2.VerifyInstalled(false);
145 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion));
146 Assert.Equal(V100, actualProviderVersion);
147 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
148
149 // Install the v1 bundle with a second parent.
150 bundleAv1.Install(arguments: parent2Switch);
151 bundleAv1.VerifyRegisteredAndInPackageCache();
152
153 packageAv1.VerifyInstalled(true);
154 packageAv2.VerifyInstalled(false);
155 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
156 Assert.Equal(V100, actualProviderVersion);
157 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
158
159 // Upgrade with the v2 bundle.
160 bundleAv2.Install();
161 bundleAv2.VerifyRegisteredAndInPackageCache();
162 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
163
164 packageAv1.VerifyInstalled(false);
165 packageAv2.VerifyInstalled(true);
166 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
167 Assert.Equal(V200, actualProviderVersion);
168 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
169 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
170
171 // Uninstall the v2 bundle and nothing should happen because there is still a parent.
172 bundleAv2.Uninstall();
173 bundleAv2.VerifyRegisteredAndInPackageCache();
174
175 packageAv1.VerifyInstalled(false);
176 packageAv2.VerifyInstalled(true);
177 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
178 Assert.Equal(V200, actualProviderVersion);
179 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
180 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
181
182 // Uninstall one parent of the v1 bundle and nothing should happen because there is still a parent.
183 bundleAv1.Uninstall(arguments: parentSwitch);
184 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
185 bundleAv2.VerifyRegisteredAndInPackageCache();
186
187 packageAv1.VerifyInstalled(false);
188 packageAv2.VerifyInstalled(true);
189 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
190 Assert.Equal(V200, actualProviderVersion);
191 Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent));
192 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
193
194 // Uninstall the v1 bundle with passthrough with second parent and all should be removed.
195 bundleAv1.Uninstall(arguments: parent2Switch);
196 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
197 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
198
199 packageAv1.VerifyInstalled(false);
200 packageAv2.VerifyInstalled(false);
201 Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
202 }
203
204 [Fact]
205 public void CanTrack2ForwardCompatibleDependentsThroughMajorUpgradePerUser()
206 {
207 string providerId = BundleCProviderId;
208 string parent = "~BundleCv1";
209 string parent2 = "~BundleCv1_Parent2";
210 string parentSwitch = String.Concat("-parent ", parent);
211 string parent2Switch = String.Concat("-parent ", parent2);
212
213 var packageCv1 = this.CreatePackageInstaller("PackageCv1");
214 var packageCv2 = this.CreatePackageInstaller("PackageCv2");
215 var bundleCv1 = this.CreateBundleInstaller("BundleCv1");
216 var bundleCv2 = this.CreateBundleInstaller("BundleCv2");
217
218 packageCv1.VerifyInstalled(false);
219 packageCv2.VerifyInstalled(false);
220
221 // Install the v1 bundle with a parent.
222 bundleCv1.Install(arguments: parentSwitch);
223 bundleCv1.VerifyRegisteredAndInPackageCache();
224
225 packageCv1.VerifyInstalled(true);
226 packageCv2.VerifyInstalled(false);
227 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion));
228 Assert.Equal(V100, actualProviderVersion);
229 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
230
231 // Install the v1 bundle with a second parent.
232 bundleCv1.Install(arguments: parent2Switch);
233 bundleCv1.VerifyRegisteredAndInPackageCache();
234
235 packageCv1.VerifyInstalled(true);
236 packageCv2.VerifyInstalled(false);
237 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
238 Assert.Equal(V100, actualProviderVersion);
239 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
240
241 // Upgrade with the v2 bundle.
242 bundleCv2.Install();
243 bundleCv2.VerifyRegisteredAndInPackageCache();
244 bundleCv1.VerifyUnregisteredAndRemovedFromPackageCache();
245
246 packageCv1.VerifyInstalled(false);
247 packageCv2.VerifyInstalled(true);
248 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
249 Assert.Equal(V200, actualProviderVersion);
250 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
251 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
252
253 // Uninstall the v2 bundle and nothing should happen because there is still a parent.
254 bundleCv2.Uninstall();
255 bundleCv2.VerifyRegisteredAndInPackageCache();
256
257 packageCv1.VerifyInstalled(false);
258 packageCv2.VerifyInstalled(true);
259 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
260 Assert.Equal(V200, actualProviderVersion);
261 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
262 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
263
264 // Uninstall one parent of the v1 bundle and nothing should happen because there is still a parent.
265 bundleCv1.Uninstall(arguments: parentSwitch);
266 bundleCv1.VerifyUnregisteredAndRemovedFromPackageCache();
267 bundleCv2.VerifyRegisteredAndInPackageCache();
268
269 packageCv1.VerifyInstalled(false);
270 packageCv2.VerifyInstalled(true);
271 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
272 Assert.Equal(V200, actualProviderVersion);
273 Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent));
274 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
275
276 // Uninstall the v1 bundle with passthrough with second parent and all should be removed.
277 bundleCv1.Uninstall(arguments: parent2Switch);
278 bundleCv1.VerifyUnregisteredAndRemovedFromPackageCache();
279 bundleCv2.VerifyUnregisteredAndRemovedFromPackageCache();
280
281 packageCv1.VerifyInstalled(false);
282 packageCv2.VerifyInstalled(false);
283 Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
284 }
285
286 [Fact]
287 public void CanTrack2ForwardCompatibleDependentsThroughMajorUpgradeWithParent()
288 {
289 string providerId = BundleAProviderId;
290 string parent = "~BundleAv1";
291 string parent2 = "~BundleAv1_Parent2";
292 string parent3 = "~BundleAv1_Parent3";
293 string parentSwitch = String.Concat("-parent ", parent);
294 string parent2Switch = String.Concat("-parent ", parent2);
295 string parent3Switch = String.Concat("-parent ", parent3);
296
297 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
298 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
299 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
300 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
301
302 packageAv1.VerifyInstalled(false);
303 packageAv2.VerifyInstalled(false);
304
305 // Install the v1 bundle with a parent.
306 bundleAv1.Install(arguments: parentSwitch);
307 bundleAv1.VerifyRegisteredAndInPackageCache();
308
309 packageAv1.VerifyInstalled(true);
310 packageAv2.VerifyInstalled(false);
311 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion));
312 Assert.Equal(V100, actualProviderVersion);
313 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
314
315 // Install the v1 bundle with a second parent.
316 bundleAv1.Install(arguments: parent2Switch);
317 bundleAv1.VerifyRegisteredAndInPackageCache();
318
319 packageAv1.VerifyInstalled(true);
320 packageAv2.VerifyInstalled(false);
321 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
322 Assert.Equal(V100, actualProviderVersion);
323 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
324
325 // Upgrade with the v2 bundle.
326 bundleAv2.Install(arguments: parent3Switch);
327 bundleAv2.VerifyRegisteredAndInPackageCache();
328 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
329
330 packageAv1.VerifyInstalled(false);
331 packageAv2.VerifyInstalled(true);
332 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
333 Assert.Equal(V200, actualProviderVersion);
334 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
335 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
336 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent3));
337
338 // Uninstall the v2 bundle and nothing should happen because there is still a parent.
339 bundleAv2.Uninstall(arguments: parent3Switch);
340 bundleAv2.VerifyRegisteredAndInPackageCache();
341
342 packageAv1.VerifyInstalled(false);
343 packageAv2.VerifyInstalled(true);
344 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
345 Assert.Equal(V200, actualProviderVersion);
346 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
347 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
348 Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent3));
349
350 // Uninstall one parent of the v1 bundle and nothing should happen because there is still a parent.
351 bundleAv1.Uninstall(arguments: parentSwitch);
352 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
353 bundleAv2.VerifyRegisteredAndInPackageCache();
354
355 packageAv1.VerifyInstalled(false);
356 packageAv2.VerifyInstalled(true);
357 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
358 Assert.Equal(V200, actualProviderVersion);
359 Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent));
360 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent2));
361
362 // Uninstall the v1 bundle with passthrough with second parent and all should be removed.
363 bundleAv1.Uninstall(arguments: parent2Switch);
364 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
365 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
366
367 packageAv1.VerifyInstalled(false);
368 packageAv2.VerifyInstalled(false);
369 Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
370 }
371
372 [Fact]
373 public void CanUninstallForwardCompatibleWithBundlesUninstalledInFifoOrder()
374 {
375 string providerId = BundleAProviderId;
376 string parent = "~BundleAv1";
377 string parentSwitch = String.Concat("-parent ", parent);
378
379 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
380 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
381 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
382 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
383
384 packageAv1.VerifyInstalled(false);
385 packageAv2.VerifyInstalled(false);
386
387 bundleAv2.Install();
388 bundleAv2.VerifyRegisteredAndInPackageCache();
389
390 packageAv1.VerifyInstalled(false);
391 packageAv2.VerifyInstalled(true);
392 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion));
393 Assert.Equal(V200, actualProviderVersion);
394
395 // Install the v1 bundle with a parent which should passthrough to v2.
396 bundleAv1.Install(arguments: parentSwitch);
397 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
398
399 packageAv1.VerifyInstalled(false);
400 packageAv2.VerifyInstalled(true);
401 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
402
403 bundleAv2.Uninstall();
404 bundleAv2.VerifyRegisteredAndInPackageCache();
405
406 packageAv1.VerifyInstalled(false);
407 packageAv2.VerifyInstalled(true);
408 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
409
410 // Uninstall the v1 bundle with passthrough and all should be removed.
411 bundleAv1.Uninstall(arguments: parentSwitch);
412 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
413 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
414
415 packageAv1.VerifyInstalled(false);
416 packageAv2.VerifyInstalled(false);
417 Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
418 }
419
420 [Fact]
421 public void CanUninstallForwardCompatibleWithBundlesUninstalledInReverseOrder()
422 {
423 string providerId = BundleAProviderId;
424 string parent = "~BundleAv1";
425 string parentSwitch = String.Concat("-parent ", parent);
426
427 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
428 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
429 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
430 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
431
432 packageAv1.VerifyInstalled(false);
433 packageAv2.VerifyInstalled(false);
434
435 bundleAv2.Install();
436 bundleAv2.VerifyRegisteredAndInPackageCache();
437
438 packageAv1.VerifyInstalled(false);
439 packageAv2.VerifyInstalled(true);
440 Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion));
441 Assert.Equal(V200, actualProviderVersion);
442
443 // Install the v1 bundle with a parent which should passthrough to v2.
444 bundleAv1.Install(arguments: parentSwitch);
445 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
446
447 packageAv1.VerifyInstalled(false);
448 packageAv2.VerifyInstalled(true);
449 Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent));
450
451 // Uninstall the v1 bundle with the same parent which should passthrough to v2 and remove parent.
452 bundleAv1.Uninstall(arguments: parentSwitch);
453 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
454 bundleAv2.VerifyRegisteredAndInPackageCache();
455
456 packageAv1.VerifyInstalled(false);
457 packageAv2.VerifyInstalled(true);
458 Assert.False(BundleRegistration.DependencyDependentExists(providerId, parent));
459
460 // Uninstall the v2 bundle and all should be removed.
461 bundleAv2.Uninstall();
462 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
463
464 packageAv1.VerifyInstalled(false);
465 packageAv2.VerifyInstalled(false);
466 Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion));
467 }
468 }
469}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.Collections.Generic;
7
8 public interface IWebServer : IDisposable
9 {
10 /// <summary>
11 /// Registers a collection of relative URLs (the key) with its absolute path to the file (the value).
12 /// </summary>
13 void AddFiles(Dictionary<string, string> physicalPathsByRelativeUrl);
14
15 /// <summary>
16 /// Starts the web server on a new thread.
17 /// </summary>
18 void Start();
19 }
20} \ 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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System.Collections.Generic;
6 using System.IO;
7 using WixBuildTools.TestSupport;
8 using Xunit;
9 using Xunit.Abstractions;
10
11 public class LayoutTests : BurnE2ETests
12 {
13 public LayoutTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
14
15 [Fact]
16 public void CanLayoutBundleInPlaceWithMissingPayloads()
17 {
18 var bundleA = this.CreateBundleInstaller("BundleA");
19 var webServer = this.CreateWebServer();
20
21 webServer.AddFiles(new Dictionary<string, string>
22 {
23 { "/BundleA/LayoutOnlyPayload", Path.Combine(this.TestContext.TestDataFolder, "BundleA.wxs") },
24 { "/BundleA/packages.cab", Path.Combine(this.TestContext.TestDataFolder, "packages.cab") },
25 });
26 webServer.Start();
27
28 using var dfs = new DisposableFileSystem();
29 var layoutDirectory = dfs.GetFolder(true);
30
31 // Manually copy bundle to layout directory and then run from there so the non-compressed payloads have to be resolved.
32 var bundleAFileInfo = new FileInfo(bundleA.Bundle);
33 var bundleACopiedPath = Path.Combine(layoutDirectory, bundleAFileInfo.Name);
34 bundleAFileInfo.CopyTo(bundleACopiedPath);
35
36 bundleA.Layout(bundleACopiedPath, layoutDirectory);
37 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
38
39 Assert.True(File.Exists(bundleACopiedPath));
40 Assert.True(File.Exists(Path.Combine(layoutDirectory, "packages.cab")));
41 Assert.True(File.Exists(Path.Combine(layoutDirectory, "BundleA.wxs")));
42 }
43
44 [Fact]
45 public void CanLayoutBundleToNewDirectory()
46 {
47 var bundleA = this.CreateBundleInstaller("BundleA");
48 var webServer = this.CreateWebServer();
49
50 webServer.AddFiles(new Dictionary<string, string>
51 {
52 { "/BundleA/LayoutOnlyPayload", Path.Combine(this.TestContext.TestDataFolder, "BundleA.wxs") },
53 { "/BundleA/packages.cab", Path.Combine(this.TestContext.TestDataFolder, "packages.cab") },
54 });
55 webServer.Start();
56
57 using var dfs = new DisposableFileSystem();
58 var layoutDirectory = dfs.GetFolder();
59
60 bundleA.Layout(layoutDirectory);
61 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
62
63 Assert.True(File.Exists(Path.Combine(layoutDirectory, "BundleA.exe")));
64 Assert.True(File.Exists(Path.Combine(layoutDirectory, "packages.cab")));
65 Assert.True(File.Exists(Path.Combine(layoutDirectory, "BundleA.wxs")));
66 }
67 }
68}
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 @@
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
3namespace 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 [Fact]
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 bundleAv1CachedPath = 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 bundleAv2CachedPath = 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(bundleAv1CachedPath);
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(bundleAv2CachedPath);
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 [Fact]
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}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.IO;
7 using System.Xml;
8 using Xunit;
9 using Xunit.Abstractions;
10
11 public class PatchTests : BurnE2ETests
12 {
13 public PatchTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
14
15 [Fact]
16 public void CanRunDetectMultipleTimesWithPatches()
17 {
18 var testBAController = this.CreateTestBAController();
19 testBAController.SetRedetectCount(1);
20
21 this.CanInstallBundleWithPatchThenRemoveIt();
22 }
23
24 [Fact]
25 public void CanInstallBundleWithPatchThenRemoveIt()
26 {
27 var originalVersion = "1.0.0.0";
28 var patchedVersion = "1.0.1.0";
29 var testRegistryValue = "PackageA";
30
31 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
32 var bundleA = this.CreateBundleInstaller("BundleA");
33 var bundlePatchA = this.CreateBundleInstaller("BundlePatchA");
34
35 bundleA.Install();
36 bundleA.VerifyRegisteredAndInPackageCache();
37
38 packageAv1.VerifyInstalled(true);
39 packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion);
40
41 bundlePatchA.Install();
42 bundlePatchA.VerifyRegisteredAndInPackageCache();
43
44 packageAv1.VerifyTestRegistryValue(testRegistryValue, patchedVersion);
45
46 bundlePatchA.Uninstall();
47 bundlePatchA.VerifyUnregisteredAndRemovedFromPackageCache();
48
49 packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion);
50
51 bundleA.Uninstall();
52 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
53
54 packageAv1.VerifyInstalled(false);
55 packageAv1.VerifyTestRegistryRootDeleted();
56 }
57
58 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6380")]
59 public void CanPatchSwidTag()
60 {
61 var originalVersion = "1.0.0.0";
62 var patchedVersion = "1.0.1.0";
63 var packageTagName = "~PatchTests - PackageA";
64 var bundleTagName = "~PatchTests - BundleA";
65 var bundlePatchTagName = "~PatchTests - BundlePatchA";
66
67 this.CreatePackageInstaller("PackageAv1");
68 var bundleA = this.CreateBundleInstaller("BundleA");
69 var bundlePatchA = this.CreateBundleInstaller("BundlePatchA");
70
71 bundleA.Install();
72 VerifySwidTagVersion(bundleTagName, originalVersion);
73 VerifySwidTagVersion(packageTagName, originalVersion);
74
75 bundlePatchA.Install();
76 VerifySwidTagVersion(bundlePatchTagName, patchedVersion);
77 VerifySwidTagVersion(packageTagName, patchedVersion);
78
79 bundlePatchA.Uninstall();
80 VerifySwidTagVersion(packageTagName, originalVersion);
81
82 bundleA.Uninstall();
83 VerifySwidTagVersion(bundleTagName, null);
84 VerifySwidTagVersion(packageTagName, null);
85 }
86
87 [Fact]
88 public void CanInstallBundleWithPatchesTargetingSingleProductThenRemoveIt()
89 {
90 var originalVersion = "1.0.0.0";
91 var patchedVersion = "1.0.1.0";
92 var testRegistryValue = "PackageA";
93 var testRegistryValue2 = "PackageA2";
94
95 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
96 var bundlePatchA2 = this.CreateBundleInstaller("BundlePatchA2");
97
98 packageAv1.InstallProduct();
99 packageAv1.VerifyInstalled(true);
100 packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion);
101 packageAv1.VerifyTestRegistryValue(testRegistryValue2, originalVersion);
102
103 bundlePatchA2.Install();
104 bundlePatchA2.VerifyRegisteredAndInPackageCache();
105
106 packageAv1.VerifyTestRegistryValue(testRegistryValue, patchedVersion);
107 packageAv1.VerifyTestRegistryValue(testRegistryValue2, patchedVersion);
108
109 bundlePatchA2.Uninstall();
110 bundlePatchA2.VerifyUnregisteredAndRemovedFromPackageCache();
111
112 packageAv1.VerifyTestRegistryValue(testRegistryValue, originalVersion);
113 packageAv1.VerifyTestRegistryValue(testRegistryValue2, originalVersion);
114 }
115
116 private static void VerifySwidTagVersion(string tagName, string expectedVersion)
117 {
118 var regidFolder = Environment.ExpandEnvironmentVariables(@"%ProgramData%\regid.1995-08.com.example");
119 var tagPath = Path.Combine(regidFolder, "regid.1995-08.com.example " + tagName + ".swidtag");
120 string version = null;
121
122 if (File.Exists(tagPath))
123 {
124 var doc = new XmlDocument();
125 doc.Load(tagPath);
126
127 var ns = new XmlNamespaceManager(doc.NameTable);
128 ns.AddNamespace("s", "http://standards.iso.org/iso/19770/-2/2009/schema.xsd");
129
130 var versionNode = doc.SelectSingleNode("/s:software_identification_tag/s:product_version/s:name", ns);
131 version = versionNode?.InnerText ?? String.Empty;
132 }
133
134 Assert.Equal(expectedVersion, version);
135 }
136 }
137}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.IO;
7 using Xunit;
8 using Xunit.Abstractions;
9
10 public class PrereqBaTests : BurnE2ETests
11 {
12 public PrereqBaTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
13
14 /// <summary>
15 /// This bundle purposely provides a .runtimeconfig.json file that requires a version of .NET Core that doesn't exist,
16 /// with an MSI package to represent the prerequisite package.
17 /// This verifies that:
18 /// The preqba doesn't infinitely reload itself after failing to load the managed BA.
19 /// The engine automatically uninstalls the bundle since only permanent packages were installed.
20 /// </summary>
21 [Fact]
22 public void DncPreqBaDetectsInfiniteLoop()
23 {
24 var packageA = this.CreatePackageInstaller("PackageA");
25 this.CreatePackageInstaller("PackageF");
26
27 var bundleA = this.CreateBundleInstaller("BundleA");
28
29 var packageASourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
30
31 // Source file should *not* be installed
32 Assert.False(File.Exists(packageASourceCodeInstalled), $"Package A payload should not be there on test start: {packageASourceCodeInstalled}");
33
34 bundleA.Install();
35
36 // Part of the test is Install actually completing.
37
38 // Source file should be installed
39 Assert.True(File.Exists(packageASourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageASourceCodeInstalled));
40
41 // No non-permanent packages should have ended up installed or cached so it should have unregistered.
42 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
43 }
44
45 /// <summary>
46 /// This bundle purposely provides a WixToolset.Mba.Host.config file that requires a version of .NET Framework that doesn't exist,
47 /// with an MSI package to represent the prerequisite package.
48 /// This verifies that:
49 /// The preqba doesn't infinitely reload itself after failing to load the managed BA.
50 /// The engine automatically uninstalls the bundle since only permanent packages were installed.
51 /// </summary>
52 [Fact]
53 public void MbaPreqBaDetectsInfiniteLoop()
54 {
55 var packageB = this.CreatePackageInstaller("PackageB");
56 this.CreatePackageInstaller("PackageF");
57
58 var bundleB = this.CreateBundleInstaller("BundleB");
59
60 var packageBSourceCodeInstalled = packageB.GetInstalledFilePath("Package.wxs");
61
62 // Source file should *not* be installed
63 Assert.False(File.Exists(packageBSourceCodeInstalled), $"Package B payload should not be there on test start: {packageBSourceCodeInstalled}");
64
65 bundleB.Install();
66
67 // Part of the test is Install actually completing.
68
69 // Source file should be installed
70 Assert.True(File.Exists(packageBSourceCodeInstalled), String.Concat("Should have found Package B payload installed at: ", packageBSourceCodeInstalled));
71
72 // No non-permanent packages should have ended up installed or cached so it should have unregistered.
73 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
74 }
75 }
76}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using Xunit;
7 using Xunit.Abstractions;
8
9 public class RegistrationTests : BurnE2ETests
10 {
11 public RegistrationTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
12
13 [Fact]
14 public void AutomaticallyUncachesBundleWhenNotInstalled()
15 {
16 var bundleA = this.CreateBundleInstaller("BundleA");
17 var testBAController = this.CreateTestBAController();
18
19 var cachedBundlePath = bundleA.ManuallyCache();
20
21 testBAController.SetQuitAfterDetect();
22
23 bundleA.Install(cachedBundlePath);
24
25 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
26 }
27
28 [Fact]
29 public void AutomaticallyUninstallsBundleWithoutBADoingApply()
30 {
31 this.InstallBundleThenManuallyUninstallPackageAndRemovePackageFromCacheThenRunAndQuitWithoutApply(true);
32 }
33
34 [Fact]
35 public void AutomaticallyUninstallsBundleWithoutBADoingDetect()
36 {
37 this.InstallBundleThenManuallyUninstallPackageAndRemovePackageFromCacheThenRunAndQuitWithoutApply(false);
38 }
39
40 [Fact]
41 public void RegistersInARPIfPrecached()
42 {
43 var bundleA = this.CreateBundleInstaller("BundleA");
44
45 bundleA.ManuallyCache();
46
47 // Verifies https://github.com/wixtoolset/issues/issues/5702
48 bundleA.Install();
49 bundleA.VerifyRegisteredAndInPackageCache();
50 }
51
52 private void InstallBundleThenManuallyUninstallPackageAndRemovePackageFromCacheThenRunAndQuitWithoutApply(bool detect)
53 {
54 var packageA = this.CreatePackageInstaller("PackageA");
55 var bundleA = this.CreateBundleInstaller("BundleA");
56 var testBAController = this.CreateTestBAController();
57
58 bundleA.Install();
59 bundleA.VerifyRegisteredAndInPackageCache();
60 packageA.VerifyInstalled(true);
61
62 packageA.UninstallProduct();
63 bundleA.RemovePackageFromCache("PackageA");
64
65 if (detect)
66 {
67 testBAController.SetQuitAfterDetect();
68 }
69 else
70 {
71 testBAController.SetImmediatelyQuit();
72 }
73 bundleA.Install();
74 packageA.VerifyInstalled(false);
75 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
76 }
77 }
78}
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 @@
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
3namespace 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) { }
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(Skip = "https://github.com/wixtoolset/issues/issues/6309")]
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}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.IO;
7 using WixTestTools;
8 using WixToolset.Mba.Core;
9 using Xunit;
10 using Xunit.Abstractions;
11
12 public class SlipstreamTests : BurnE2ETests
13 {
14 public SlipstreamTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
15
16 private const string V090 = "0.9.0.0";
17 private const string V100 = "1.0.0.0";
18 private const string V101 = "1.0.1.0";
19
20 [Fact]
21 public void CanInstallBundleWithSlipstreamedPatchThenRemoveIt()
22 {
23 var testRegistryValue = "PackageA";
24
25 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
26 var bundleA = this.CreateBundleInstaller("BundleA");
27
28 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
29 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
30
31 bundleA.Install();
32 bundleA.VerifyRegisteredAndInPackageCache();
33 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
34 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
35
36 bundleA.Uninstall();
37 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
38 Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled));
39 packageAv1.VerifyTestRegistryRootDeleted();
40 }
41
42 /// <summary>
43 /// BundleA installs PackageA with slipstreamed PatchA.
44 /// BundleOnlyPatchA is installed which contains PatchA (which should be a no-op).
45 /// BundleOnlyPatchA in uninstalled which should do nothing since BundleA has a dependency on it.
46 /// Bundle is installed which should remove everything.
47 /// </summary>
48 [Fact]
49 public void ReferenceCountsSlipstreamedPatch()
50 {
51 var testRegistryValue = "PackageA";
52
53 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
54 var bundleOnlyPatchA = this.CreateBundleInstaller("BundleOnlyPatchA");
55 var bundleA = this.CreateBundleInstaller("BundleA");
56
57 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
58 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
59
60 bundleA.Install();
61 bundleA.VerifyRegisteredAndInPackageCache();
62 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
63 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
64
65 bundleOnlyPatchA.Install();
66 bundleOnlyPatchA.VerifyRegisteredAndInPackageCache();
67 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
68 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
69
70 bundleOnlyPatchA.Uninstall();
71 bundleOnlyPatchA.VerifyUnregisteredAndRemovedFromPackageCache();
72 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
73 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
74
75 bundleA.Uninstall();
76 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
77 Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled));
78 packageAv1.VerifyTestRegistryRootDeleted();
79 }
80
81 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6350")]
82 public void CanInstallBundleWithSlipstreamedPatchThenRepairIt()
83 {
84 this.InstallBundleWithSlipstreamedPatchThenRepairIt(false);
85 }
86
87 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6350")]
88 public void CanInstallReversedBundleWithSlipstreamedPatchThenRepairIt()
89 {
90 this.InstallBundleWithSlipstreamedPatchThenRepairIt(true);
91 }
92
93 private void InstallBundleWithSlipstreamedPatchThenRepairIt(bool isReversed)
94 {
95 var bundleName = isReversed ? "BundleAReverse" : "BundleA";
96 var testRegistryValue = "PackageA";
97
98 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
99 var bundleA = this.CreateBundleInstaller(bundleName);
100
101 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
102 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
103
104 bundleA.Install();
105 bundleA.VerifyRegisteredAndInPackageCache();
106 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
107 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
108
109 // Delete the installed file and registry key so we have something to repair.
110 File.Delete(packageAv1SourceCodeInstalled);
111 packageAv1.DeleteTestRegistryValue(testRegistryValue);
112
113 bundleA.Repair();
114 bundleA.VerifyRegisteredAndInPackageCache();
115 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
116 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
117
118 bundleA.Uninstall();
119 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
120 Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled));
121 packageAv1.VerifyTestRegistryRootDeleted();
122 }
123
124 [Fact]
125 public void CanInstallSlipstreamedPatchThroughForcedRepair()
126 {
127 this.InstallSlipstreamedPatchThroughForcedRepair(false);
128 }
129
130 [Fact]
131 public void CanInstallSlipstreamedPatchThroughReversedForcedRepair()
132 {
133 this.InstallSlipstreamedPatchThroughForcedRepair(true);
134 }
135
136 private void InstallSlipstreamedPatchThroughForcedRepair(bool isReversed)
137 {
138 var bundleName = isReversed ? "BundleAReverse" : "BundleA";
139 var testRegistryValue = "PackageA";
140
141 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
142 var bundleA = this.CreateBundleInstaller(bundleName);
143 var bundleOnlyA = this.CreateBundleInstaller("BundleOnlyA");
144 var testBAController = this.CreateTestBAController();
145
146 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
147 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
148
149 bundleOnlyA.Install();
150 bundleOnlyA.VerifyRegisteredAndInPackageCache();
151 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
152 packageAv1.VerifyTestRegistryValue(testRegistryValue, V100);
153
154 // Delete the installed file and registry key so we have something to repair.
155 File.Delete(packageAv1SourceCodeInstalled);
156 packageAv1.DeleteTestRegistryValue(testRegistryValue);
157
158 testBAController.SetPackageRequestedState("PackageA", RequestState.Repair);
159 testBAController.SetPackageRequestedState("PatchA", RequestState.Repair);
160
161 bundleA.Install();
162 bundleA.VerifyRegisteredAndInPackageCache();
163 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
164 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
165
166 testBAController.ResetPackageStates("PackageA");
167 testBAController.ResetPackageStates("PatchA");
168
169 bundleA.Uninstall();
170 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
171 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
172 packageAv1.VerifyTestRegistryValue(testRegistryValue, V100);
173
174 bundleOnlyA.Uninstall();
175 bundleOnlyA.VerifyUnregisteredAndRemovedFromPackageCache();
176 Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled));
177 packageAv1.VerifyTestRegistryRootDeleted();
178 }
179
180 [Fact]
181 public void CanUninstallSlipstreamedPatchAlone()
182 {
183 var testRegistryValue = "PackageA";
184
185 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
186 var bundleA = this.CreateBundleInstaller("BundleA");
187 var testBAController = this.CreateTestBAController();
188
189 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
190 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
191
192 bundleA.Install();
193 bundleA.VerifyRegisteredAndInPackageCache();
194 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
195 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
196
197 testBAController.SetPackageRequestedState("PatchA", RequestState.Absent);
198
199 bundleA.Modify();
200 bundleA.VerifyRegisteredAndInPackageCache();
201 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
202 packageAv1.VerifyTestRegistryValue(testRegistryValue, V100);
203
204 bundleA.Uninstall();
205 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
206 Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled));
207 packageAv1.VerifyTestRegistryRootDeleted();
208 }
209
210 [Fact]
211 public void CanModifyToUninstallPackageWithSlipstreamedPatch()
212 {
213 var testRegistryValue = "PackageA";
214
215 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
216 var packageBv1 = this.CreatePackageInstaller("PackageBv1");
217 var bundleB = this.CreateBundleInstaller("BundleB");
218 var testBAController = this.CreateTestBAController();
219
220 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
221 var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs");
222 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
223 Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"PackageBv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}");
224
225 bundleB.Install();
226 bundleB.VerifyRegisteredAndInPackageCache();
227 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
228 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
229 Assert.True(File.Exists(packageBv1SourceCodeInstalled), String.Concat("Should have found PackageBv1 payload installed at: ", packageBv1SourceCodeInstalled));
230
231 testBAController.SetPackageRequestedState("PackageA", RequestState.Absent);
232 testBAController.SetPackageRequestedState("PatchA", RequestState.Absent);
233
234 bundleB.Modify();
235 bundleB.VerifyRegisteredAndInPackageCache();
236 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should have been removed by modify from: {packageAv1SourceCodeInstalled}");
237
238 testBAController.ResetPackageStates("PackageA");
239 testBAController.ResetPackageStates("PatchA");
240
241 bundleB.Uninstall();
242 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
243 Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("PackageBv1 payload should have been removed by uninstall from: ", packageBv1SourceCodeInstalled));
244 packageBv1.VerifyTestRegistryRootDeleted();
245 }
246
247 [Fact]
248 public void UninstallsPackageWithSlipstreamedPatchDuringRollback()
249 {
250 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
251 var packageBv1 = this.CreatePackageInstaller("PackageBv1");
252 var bundleB = this.CreateBundleInstaller("BundleB");
253 var testBAController = this.CreateTestBAController();
254
255 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
256 var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs");
257 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
258 Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"PackageBv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}");
259
260 testBAController.SetPackageCancelExecuteAtProgress("PackageB", 50);
261
262 bundleB.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
263 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
264 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should have been removed by rollback from: {packageAv1SourceCodeInstalled}");
265 Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("PackageBv1 payload should not have been installed from: ", packageBv1SourceCodeInstalled));
266 packageBv1.VerifyTestRegistryRootDeleted();
267 }
268
269 [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6359")]
270 public void CanAutomaticallyPredetermineSlipstreamPatchesAtBuildTime()
271 {
272 var testRegistryValueA = "PackageA";
273 var testRegistryValueA2 = "PackageA2";
274 var testRegistryValueB = "PackageB";
275 var testRegistryValueB2 = "PackageB2";
276
277 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
278 var packageBv1 = this.CreatePackageInstaller("PackageBv1");
279 var bundleC = this.CreateBundleInstaller("BundleC");
280
281 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
282 var packageBv1SourceCodeInstalled = packageBv1.GetInstalledFilePath("Package.wxs");
283 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
284 Assert.False(File.Exists(packageBv1SourceCodeInstalled), $"PackageBv1 payload should not be there on test start: {packageBv1SourceCodeInstalled}");
285
286 bundleC.Install();
287 bundleC.VerifyRegisteredAndInPackageCache();
288 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
289 // Product A should've slipstreamed both patches.
290 packageAv1.VerifyTestRegistryValue(testRegistryValueA, V101);
291 packageAv1.VerifyTestRegistryValue(testRegistryValueA2, V101);
292 // Product B should've only slipstreamed patch AB2.
293 packageBv1.VerifyTestRegistryValue(testRegistryValueB, V100);
294 packageBv1.VerifyTestRegistryValue(testRegistryValueB2, V101);
295
296 bundleC.Uninstall();
297 bundleC.VerifyUnregisteredAndRemovedFromPackageCache();
298 Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled));
299 Assert.False(File.Exists(packageBv1SourceCodeInstalled), String.Concat("PackageBv1 payload should have been removed by uninstall from: ", packageBv1SourceCodeInstalled));
300 packageAv1.VerifyTestRegistryRootDeleted();
301 }
302
303 [Fact]
304 public void CanInstallSlipstreamedPatchWithPackageDuringMajorUpgrade()
305 {
306 var testRegistryValue = "PackageA";
307
308 var packageAv0 = this.CreatePackageInstaller("PackageAv0_9_0");
309 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
310 var bundleA = this.CreateBundleInstaller("BundleA");
311
312 packageAv1.VerifyInstalled(false);
313
314 packageAv0.InstallProduct();
315 packageAv0.VerifyInstalled(true);
316 packageAv1.VerifyTestRegistryValue(testRegistryValue, V090);
317
318 bundleA.Install();
319 bundleA.VerifyRegisteredAndInPackageCache();
320 packageAv0.VerifyInstalled(false);
321 packageAv1.VerifyInstalled(true);
322 packageAv1.VerifyTestRegistryValue(testRegistryValue, V101);
323
324 bundleA.Uninstall();
325 bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
326 packageAv1.VerifyInstalled(false);
327 packageAv1.VerifyTestRegistryRootDeleted();
328 }
329
330 [Fact]
331 public void RespectsSlipstreamedPatchInstallCondition()
332 {
333 var testRegistryValue = "PackageA";
334
335 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
336 var bundleD = this.CreateBundleInstaller("BundleD");
337
338 var packageAv1SourceCodeInstalled = packageAv1.GetInstalledFilePath("Package.wxs");
339 Assert.False(File.Exists(packageAv1SourceCodeInstalled), $"PackageAv1 payload should not be there on test start: {packageAv1SourceCodeInstalled}");
340
341 bundleD.Install();
342 bundleD.VerifyRegisteredAndInPackageCache();
343 Assert.True(File.Exists(packageAv1SourceCodeInstalled), String.Concat("Should have found PackageAv1 payload installed at: ", packageAv1SourceCodeInstalled));
344 // The patch was not supposed to be installed.
345 packageAv1.VerifyTestRegistryValue(testRegistryValue, V100);
346
347 bundleD.Uninstall();
348 bundleD.VerifyUnregisteredAndRemovedFromPackageCache();
349 Assert.False(File.Exists(packageAv1SourceCodeInstalled), String.Concat("PackageAv1 payload should have been removed by uninstall from: ", packageAv1SourceCodeInstalled));
350 packageAv1.VerifyTestRegistryRootDeleted();
351 }
352 }
353}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using Microsoft.Win32;
7 using WixTestTools;
8 using WixToolset.Mba.Core;
9
10 public class TestBAController : IDisposable
11 {
12 public TestBAController(WixTestContext testContext, bool x64 = false)
13 {
14 this.TestGroupName = testContext.TestGroupName;
15 this.BaseRegKeyPath = x64 ? @"Software\WiX\Tests" : @"Software\WOW6432Node\WiX\Tests";
16 this.TestBaseRegKeyPath = String.Format(@"{0}\TestBAControl\{1}", this.BaseRegKeyPath, this.TestGroupName);
17 }
18
19 private string BaseRegKeyPath { get; }
20
21 private string TestBaseRegKeyPath { get; }
22
23 public string TestGroupName { get; }
24
25 /// <summary>
26 /// Sets a test value in the registry to communicate with the TestBA.
27 /// </summary>
28 /// <param name="name">Name of the value to set.</param>
29 /// <param name="value">Value to set. If this is null, the value is removed.</param>
30 public void SetBurnTestValue(string name, string value)
31 {
32 using (var testKey = Registry.LocalMachine.CreateSubKey(this.TestBaseRegKeyPath))
33 {
34 if (String.IsNullOrEmpty(value))
35 {
36 testKey.DeleteValue(name, false);
37 }
38 else
39 {
40 testKey.SetValue(name, value);
41 }
42 }
43 }
44
45 public void SetExplicitlyElevateAndPlanFromOnElevateBegin(string value = "true")
46 {
47 this.SetBurnTestValue("ExplicitlyElevateAndPlanFromOnElevateBegin", value);
48 }
49
50 public void SetImmediatelyQuit(string value = "true")
51 {
52 this.SetBurnTestValue("ImmediatelyQuit", value);
53 }
54
55 public void SetQuitAfterDetect(string value = "true")
56 {
57 this.SetBurnTestValue("QuitAfterDetect", value);
58 }
59
60 /// <summary>
61 /// Slows the cache progress of a package.
62 /// </summary>
63 /// <param name="packageId">Package identity.</param>
64 /// <param name="delay">Sets or removes the delay on a package being cached.</param>
65 public void SetPackageSlowCache(string packageId, int? delay)
66 {
67 this.SetPackageState(packageId, "SlowCache", delay.HasValue ? delay.ToString() : null);
68 }
69
70 /// <summary>
71 /// Cancels the cache of a package at a particular progress point.
72 /// </summary>
73 /// <param name="packageId">Package identity.</param>
74 /// <param name="cancelPoint">Sets or removes the cancel progress on a package being cached.</param>
75 public void SetPackageCancelCacheAtProgress(string packageId, int? cancelPoint)
76 {
77 this.SetPackageState(packageId, "CancelCacheAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null);
78 }
79
80 /// <summary>
81 /// Slows the execute progress of a package.
82 /// </summary>
83 /// <param name="packageId">Package identity.</param>
84 /// <param name="delay">Sets or removes the delay on a package being executed.</param>
85 public void SetPackageSlowExecute(string packageId, int? delay)
86 {
87 this.SetPackageState(packageId, "SlowExecute", delay.HasValue ? delay.ToString() : null);
88 }
89
90 /// <summary>
91 /// Cancels the execute of a package at a particular progress point.
92 /// </summary>
93 /// <param name="packageId">Package identity.</param>
94 /// <param name="cancelPoint">Sets or removes the cancel progress on a package being executed.</param>
95 public void SetPackageCancelExecuteAtProgress(string packageId, int? cancelPoint)
96 {
97 this.SetPackageState(packageId, "CancelExecuteAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null);
98 }
99
100 /// <summary>
101 /// Cancels the execute of a package at the next progess after the specified MSI action start.
102 /// </summary>
103 /// <param name="packageId">Package identity.</param>
104 /// <param name="actionName">Sets or removes the cancel progress on a package being executed.</param>
105 public void SetPackageCancelExecuteAtActionStart(string packageId, string actionName)
106 {
107 this.SetPackageState(packageId, "CancelExecuteAtActionStart", actionName);
108 }
109
110 /// <summary>
111 /// Cancels the execute of a package at a particular OnProgress point.
112 /// </summary>
113 /// <param name="packageId">Package identity.</param>
114 /// <param name="cancelPoint">Sets or removes the cancel OnProgress point on a package being executed.</param>
115 public void SetPackageCancelOnProgressAtProgress(string packageId, int? cancelPoint)
116 {
117 this.SetPackageState(packageId, "CancelOnProgressAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null);
118 }
119
120 /// <summary>
121 /// Sets the requested state for a package that the TestBA will return to the engine during plan.
122 /// </summary>
123 /// <param name="packageId">Package identity.</param>
124 /// <param name="state">State to request.</param>
125 public void SetPackageRequestedState(string packageId, RequestState state)
126 {
127 this.SetPackageState(packageId, "Requested", state.ToString());
128 }
129
130 /// <summary>
131 /// Sets the requested state for a package that the TestBA will return to the engine during plan.
132 /// </summary>
133 /// <param name="packageId">Package identity.</param>
134 /// <param name="state">State to request.</param>
135 public void SetPackageFeatureState(string packageId, string featureId, FeatureState state)
136 {
137 this.SetPackageState(packageId, String.Concat(featureId, "Requested"), state.ToString());
138 }
139
140 /// <summary>
141 /// Sets the number of times to re-run the Detect phase.
142 /// </summary>
143 /// <param name="state">Number of times to run Detect (after the first, normal, Detect).</param>
144 public void SetRedetectCount(int redetectCount)
145 {
146 this.SetPackageState(null, "RedetectCount", redetectCount.ToString());
147 }
148
149 /// <summary>
150 /// Resets the state for a package that the TestBA will return to the engine during plan.
151 /// </summary>
152 /// <param name="packageId">Package identity.</param>
153 public void ResetPackageStates(string packageId)
154 {
155 var key = String.Format(@"{0}\{1}", this.TestBaseRegKeyPath, packageId ?? String.Empty);
156 Registry.LocalMachine.DeleteSubKey(key);
157 }
158
159 public void SetVerifyArguments(string verifyArguments)
160 {
161 this.SetBurnTestValue("VerifyArguments", verifyArguments);
162
163 }
164
165 private void SetPackageState(string packageId, string name, string value)
166 {
167 var key = String.Format(@"{0}\{1}", this.TestBaseRegKeyPath, packageId ?? String.Empty);
168 using (var packageKey = Registry.LocalMachine.CreateSubKey(key))
169 {
170 if (String.IsNullOrEmpty(value))
171 {
172 packageKey.DeleteValue(name, false);
173 }
174 else
175 {
176 packageKey.SetValue(name, value);
177 }
178 }
179 }
180
181 public void Dispose()
182 {
183 Registry.LocalMachine.DeleteSubKeyTree($@"{this.BaseRegKeyPath}\{this.TestGroupName}", false);
184 Registry.LocalMachine.DeleteSubKeyTree($@"{this.BaseRegKeyPath}\TestBAControl", false);
185 }
186 }
187}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.IO;
9 using Xunit;
10 using Xunit.Abstractions;
11
12 public class UpdateBundleTests : BurnE2ETests
13 {
14 public UpdateBundleTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
15
16 [Fact]
17 public void CanLaunchUpdateBundleFromLocalSourceInsteadOfInstall()
18 {
19 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
20 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
21 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
22 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
23
24 var updateBundleSwitch = String.Concat("\"", "-updatebundle:", bundleAv2.Bundle, "\"");
25
26 packageAv1.VerifyInstalled(false);
27 packageAv2.VerifyInstalled(false);
28
29 // Install the v2 bundle by getting v1 to launch it as an update bundle.
30 bundleAv1.Install(arguments: updateBundleSwitch);
31 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
32 bundleAv2.VerifyRegisteredAndInPackageCache();
33
34 packageAv1.VerifyInstalled(false);
35 packageAv2.VerifyInstalled(true);
36
37 bundleAv2.Uninstall();
38 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
39 packageAv2.VerifyInstalled(false);
40 }
41
42 [Fact]
43 public void CanLaunchUpdateBundleFromLocalSourceInsteadOfModify()
44 {
45 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
46 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
47 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
48 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
49
50 var updateBundleSwitch = String.Concat("\"", "-updatebundle:", bundleAv2.Bundle, "\"");
51
52 packageAv1.VerifyInstalled(false);
53 packageAv2.VerifyInstalled(false);
54
55 bundleAv1.Install();
56 bundleAv1.VerifyRegisteredAndInPackageCache();
57
58 packageAv1.VerifyInstalled(true);
59 packageAv2.VerifyInstalled(false);
60
61 // Install the v2 bundle by getting v1 to launch it as an update bundle.
62 bundleAv1.Modify(arguments: updateBundleSwitch);
63 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
64 bundleAv2.VerifyRegisteredAndInPackageCache();
65
66 packageAv1.VerifyInstalled(false);
67 packageAv2.VerifyInstalled(true);
68
69 bundleAv2.Uninstall();
70 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
71 packageAv2.VerifyInstalled(false);
72 }
73
74 [Fact]
75 public void ForwardsArgumentsToUpdateBundle()
76 {
77 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
78 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
79 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
80 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
81 var testBAController = this.CreateTestBAController();
82
83 const string verifyArguments = "these arguments should exist";
84 var updateBundleSwitch = String.Concat("\"", "-updatebundle:", bundleAv2.Bundle, "\" ", verifyArguments);
85
86 testBAController.SetVerifyArguments(verifyArguments);
87
88 packageAv1.VerifyInstalled(false);
89 packageAv2.VerifyInstalled(false);
90
91 // Install the v2 bundle by getting v1 to launch it as an update bundle.
92 bundleAv1.Install(arguments: updateBundleSwitch);
93 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
94 bundleAv2.VerifyRegisteredAndInPackageCache();
95
96 packageAv1.VerifyInstalled(false);
97 packageAv2.VerifyInstalled(true);
98
99 // Attempt to uninstall bundleA2 without the verify arguments passed and expect failure code.
100 bundleAv2.Uninstall(expectedExitCode: -1);
101
102 // Remove the required arguments and uninstall again.
103 testBAController.SetVerifyArguments(null);
104 bundleAv2.Uninstall();
105 bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
106 packageAv2.VerifyInstalled(false);
107 }
108
109 // Installs bundle Bv1.0 then tries to update to latest version during modify (but no server exists).
110 [Fact]
111 public void CanCheckUpdateServerDuringModifyAndDoNothingWhenServerIsntResponsive()
112 {
113 var packageB = this.CreatePackageInstaller("PackageBv1");
114 var bundleB = this.CreateBundleInstaller("BundleBv1");
115
116 packageB.VerifyInstalled(false);
117
118 bundleB.Install();
119 bundleB.VerifyRegisteredAndInPackageCache();
120
121 packageB.VerifyInstalled(true);
122
123 // Run the v1 bundle requesting an update bundle.
124 bundleB.Modify(arguments: "-checkupdate");
125 bundleB.VerifyRegisteredAndInPackageCache();
126
127 // Verify nothing changed.
128 packageB.VerifyInstalled(true);
129
130 bundleB.Uninstall();
131 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
132 packageB.VerifyInstalled(false);
133 }
134
135 // Installs bundle Bv1.0 then tries to update to latest version during modify (server exists, no feed).
136 [Fact]
137 public void CanCheckUpdateServerDuringModifyAndDoNothingWhenFeedIsMissing()
138 {
139 var packageB = this.CreatePackageInstaller("PackageBv1");
140 var bundleB = this.CreateBundleInstaller("BundleBv1");
141 var webServer = this.CreateWebServer();
142
143 webServer.Start();
144
145 packageB.VerifyInstalled(false);
146
147 bundleB.Install();
148 bundleB.VerifyRegisteredAndInPackageCache();
149
150 packageB.VerifyInstalled(true);
151
152 // Run the v1 bundle requesting an update bundle.
153 bundleB.Modify(arguments: "-checkupdate");
154 bundleB.VerifyRegisteredAndInPackageCache();
155
156 // Verify nothing changed.
157 packageB.VerifyInstalled(true);
158
159 bundleB.Uninstall();
160 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
161 packageB.VerifyInstalled(false);
162 }
163
164 // Installs bundle Bv1.0 then tries to update to latest version during modify (server exists, v1.0 feed).
165 [Fact]
166 public void CanCheckUpdateServerDuringModifyAndDoNothingWhenAlreadyLatestVersion()
167 {
168 var packageB = this.CreatePackageInstaller("PackageBv1");
169 var bundleB = this.CreateBundleInstaller("BundleBv1");
170 var webServer = this.CreateWebServer();
171
172 webServer.AddFiles(new Dictionary<string, string>
173 {
174 { "/BundleB/feed", Path.Combine(this.TestContext.TestDataFolder, "FeedBv1.0.xml") },
175 });
176 webServer.Start();
177
178 packageB.VerifyInstalled(false);
179
180 bundleB.Install();
181 bundleB.VerifyRegisteredAndInPackageCache();
182
183 packageB.VerifyInstalled(true);
184
185 // Run the v1 bundle requesting an update bundle.
186 bundleB.Modify(arguments: "-checkupdate");
187 bundleB.VerifyRegisteredAndInPackageCache();
188
189 // Verify nothing changed.
190 packageB.VerifyInstalled(true);
191
192 bundleB.Uninstall();
193 bundleB.VerifyUnregisteredAndRemovedFromPackageCache();
194 packageB.VerifyInstalled(false);
195 }
196
197 // Installs bundle Bv1.0 then does an update to bundle Bv2.0 during modify (server exists, v2.0 feed).
198 [Fact]
199 public void CanLaunchUpdateBundleFromDownloadInsteadOfModify()
200 {
201 var packageBv1 = this.CreatePackageInstaller("PackageBv1");
202 var packageBv2 = this.CreatePackageInstaller("PackageBv2");
203 var bundleBv1 = this.CreateBundleInstaller("BundleBv1");
204 var bundleBv2 = this.CreateBundleInstaller("BundleBv2");
205 var webServer = this.CreateWebServer();
206
207 webServer.AddFiles(new Dictionary<string, string>
208 {
209 { "/BundleB/feed", Path.Combine(this.TestContext.TestDataFolder, "FeedBv2.0.xml") },
210 { "/BundleB/2.0/BundleB.exe", bundleBv2.Bundle },
211 });
212 webServer.Start();
213
214 packageBv1.VerifyInstalled(false);
215 packageBv2.VerifyInstalled(false);
216
217 bundleBv1.Install();
218 bundleBv1.VerifyRegisteredAndInPackageCache();
219
220 packageBv1.VerifyInstalled(true);
221 packageBv2.VerifyInstalled(false);
222
223 // Run the v1 bundle requesting an update bundle.
224 bundleBv1.Modify(arguments: "-checkupdate");
225
226 // The modify -> update is asynchronous, so we need to wait until the real BundleB is done
227 var childBundles = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(bundleBv2.Bundle));
228 foreach (var childBundle in childBundles)
229 {
230 childBundle.WaitForExit();
231 }
232
233 bundleBv1.VerifyUnregisteredAndRemovedFromPackageCache();
234 bundleBv2.VerifyRegisteredAndInPackageCache();
235
236 packageBv1.VerifyInstalled(false);
237 packageBv2.VerifyInstalled(true);
238
239 bundleBv2.Uninstall();
240 bundleBv2.VerifyUnregisteredAndRemovedFromPackageCache();
241 packageBv1.VerifyInstalled(false);
242 packageBv2.VerifyInstalled(false);
243 }
244 }
245}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.IO;
7 using WixTestTools;
8 using Xunit;
9 using Xunit.Abstractions;
10
11 public class UpgradeRelatedBundleTests : BurnE2ETests
12 {
13 public UpgradeRelatedBundleTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
14
15 [Fact]
16 public void ReportsRelatedBundleMissingFromCache()
17 {
18 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
19 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
20 var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
21 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
22
23 bundleAv1.Install();
24 bundleAv1.VerifyRegisteredAndInPackageCache();
25
26 bundleAv1.ManuallyUncache();
27
28 // Verify https://github.com/wixtoolset/issues/issues/4991
29 var bundleAv2InstallLogFilePath = bundleAv2.Install();
30 bundleAv2.VerifyRegisteredAndInPackageCache();
31
32 Assert.True(LogVerifier.MessageInLogFileRegex(bundleAv2InstallLogFilePath, @"OnDetectRelatedBundle\(\) - id: \{[0-9A-Za-z\-]{36}\}, missing from cache: True"));
33 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"));
34 }
35 }
36}
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 @@
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
3namespace WixToolsetTest.BurnE2E
4{
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using Microsoft.AspNetCore.Builder;
9 using Microsoft.AspNetCore.Hosting;
10 using Microsoft.Extensions.FileProviders;
11 using Microsoft.Extensions.FileProviders.Physical;
12 using Microsoft.Extensions.Hosting;
13 using Microsoft.Extensions.Primitives;
14
15 public class CoreOwinWebServer : IWebServer, IFileProvider
16 {
17 private Dictionary<string, string> PhysicalPathsByRelativeUrl { get; } = new Dictionary<string, string>();
18
19 private IHost WebHost { get; set; }
20
21 public void AddFiles(Dictionary<string, string> physicalPathsByRelativeUrl)
22 {
23 foreach (var kvp in physicalPathsByRelativeUrl)
24 {
25 this.PhysicalPathsByRelativeUrl.Add(kvp.Key, kvp.Value);
26 }
27 }
28
29 public void Start()
30 {
31 this.WebHost = Host.CreateDefaultBuilder()
32 .ConfigureWebHostDefaults(webBuilder =>
33 {
34 // Use localhost instead of * to avoid firewall issues.
35 webBuilder.UseUrls("http://localhost:9999");
36 webBuilder.Configure(appBuilder =>
37 {
38 appBuilder.UseStaticFiles(new StaticFileOptions
39 {
40 FileProvider = this,
41 RequestPath = "/e2e",
42 ServeUnknownFileTypes = true,
43 });
44 });
45 })
46 .Build();
47 this.WebHost.Start();
48 }
49
50 public void Dispose()
51 {
52 var waitTime = TimeSpan.FromSeconds(5);
53 this.WebHost?.StopAsync(waitTime).Wait(waitTime);
54 }
55
56 public IDirectoryContents GetDirectoryContents(string subpath) => throw new NotImplementedException();
57
58 public IFileInfo GetFileInfo(string subpath)
59 {
60 if (this.PhysicalPathsByRelativeUrl.TryGetValue(subpath, out var filepath))
61 {
62 return new PhysicalFileInfo(new FileInfo(filepath));
63 }
64
65 return new NotFoundFileInfo(subpath);
66 }
67
68 public IChangeToken Watch(string filter) => throw new NotImplementedException();
69 }
70} \ 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 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 <PlatformTarget>x64</PlatformTarget>
8 <RollForward>Major</RollForward>
9 </PropertyGroup>
10
11 <ItemGroup>
12 <Content Include="runtests.cmd" CopyToOutputDirectory="PreserveNewest" />
13 </ItemGroup>
14
15 <ItemGroup>
16 <ProjectReference Include="..\WixTestTools\WixTestTools.csproj" />
17 </ItemGroup>
18
19 <ItemGroup>
20 <PackageReference Include="Microsoft.AspNetCore.Owin" Version="3.1.13" />
21 <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
22 <PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
23 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.50" />
24 <PackageReference Include="WixToolset.Data" Version="4.0.218" />
25 <PackageReference Include="WixToolset.Mba.Core" Version="4.0.58" />
26 </ItemGroup>
27
28 <ItemGroup>
29 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
30 <PackageReference Include="xunit" Version="2.4.1" />
31 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
32 </ItemGroup>
33</Project>
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 @@
1SET RuntimeTestsEnabled=true
2dotnet test WixToolsetTest.BurnE2E.dll -v normal \ No newline at end of file