diff options
author | Rob Mensching <rob@firegiant.com> | 2021-04-22 17:12:34 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2021-05-05 11:18:35 -0700 |
commit | d8e47230e094a506406a83eb78916abf2668b29c (patch) | |
tree | 2213ee3ed1a19fd5cd19a5914a23b7f7a57318ff /src/test/burn/WixToolsetTest.BurnE2E | |
parent | 2cbe83832cc76aa379b29665de5523e82c543acf (diff) | |
download | wix-d8e47230e094a506406a83eb78916abf2668b29c.tar.gz wix-d8e47230e094a506406a83eb78916abf2668b29c.tar.bz2 wix-d8e47230e094a506406a83eb78916abf2668b29c.zip |
Move Integration into test
Diffstat (limited to 'src/test/burn/WixToolsetTest.BurnE2E')
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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace WixToolsetTest.BurnE2E | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixTestTools; | ||
8 | using Xunit; | ||
9 | using Xunit.Abstractions; | ||
10 | |||
11 | public class 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace WixToolsetTest.BurnE2E | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixTestTools; | ||
8 | using Xunit; | ||
9 | using Xunit.Abstractions; | ||
10 | |||
11 | public class MsiTransactionTests : BurnE2ETests | ||
12 | { | ||
13 | public MsiTransactionTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | ||
14 | |||
15 | [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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace WixToolsetTest.BurnE2E | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using Xunit; | ||
8 | using Xunit.Abstractions; | ||
9 | |||
10 | public class RollbackBoundaryTests : BurnE2ETests | ||
11 | { | ||
12 | public RollbackBoundaryTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | ||
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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace 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 | |||
3 | namespace WixToolsetTest.BurnE2E | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using WixTestTools; | ||
8 | using Xunit; | ||
9 | using Xunit.Abstractions; | ||
10 | |||
11 | public class 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 | |||
3 | namespace 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 @@ | |||
1 | SET RuntimeTestsEnabled=true | ||
2 | dotnet test WixToolsetTest.BurnE2E.dll -v normal \ No newline at end of file | ||