@joebigelow / wix-1 / commits / 81721d62

Port CancelEarly and CancelLate failure tests from old repo.

Sean Hall committed Jan 19, 2021 at 12:49 UTC 81721d622e7ba2983d8e8b484edee26dbe507228
14 files changed +551 -84
src/TestData/FailureTests/BundleA/BundleA.wixproj new
+19
@@ -0,0 +1,19 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + <UpgradeCode>{FE5197EB-E324-411E-B3AC-760E566E1000}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <ProjectReference Include="..\PackageA\PackageA.wixproj" />
12 + <ProjectReference Include="..\PackageB\PackageB.wixproj" />
13 + <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
14 + </ItemGroup>
15 + <ItemGroup>
16 + <PackageReference Include="WixToolset.Bal.wixext" Version="4.0.80" />
17 + <PackageReference Include="WixToolset.NetFx.wixext" Version="4.0.57" />
18 + </ItemGroup>
19 +</Project>
\ No newline at end of file
src/TestData/FailureTests/BundleA/BundleA.wxs new
+11
@@ -0,0 +1,11 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +
3 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 + <Fragment>
6 + <PackageGroup Id="BundlePackages">
7 + <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" />
8 + <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" />
9 + </PackageGroup>
10 + </Fragment>
11 +</Wix>
src/TestData/FailureTests/PackageA/PackageA.wixproj new
+9
@@ -0,0 +1,9 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{82FB39B2-56FA-4631-AA03-8B8D3215E6AE}</UpgradeCode>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
8 + </ItemGroup>
9 +</Project>
\ No newline at end of file
src/TestData/FailureTests/PackageB/PackageB.wixproj new
+9
@@ -0,0 +1,9 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <UpgradeCode>{94160B95-81DD-4DAB-AE2D-246A9E3A108E}</UpgradeCode>
5 + </PropertyGroup>
6 + <ItemGroup>
7 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
8 + </ItemGroup>
9 +</Project>
\ No newline at end of file
src/WixToolsetTest.BurnE2E/BundleInstaller.cs
+1 -76
@@ -4,20 +4,10 @@ namespace WixToolsetTest.BurnE2E
4 {
5 using System;
6 using System.IO;
7 - using System.Linq;
7 using System.Text;
9 - using Microsoft.Win32;
10 - using WixToolset.Data;
11 - using WixToolset.Data.Symbols;
12 - using Xunit;
8
14 - public class BundleInstaller : IDisposable
9 + public partial class BundleInstaller : IDisposable
10 {
16 - public const string BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
17 - public const string BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH = "BundleCachePath";
18 - public const string FULL_BURN_POLICY_REGISTRY_PATH = "SOFTWARE\\WOW6432Node\\Policies\\WiX\\Burn";
19 - public const string PACKAGE_CACHE_FOLDER_NAME = "Package Cache";
20 -
11 public BundleInstaller(WixTestContext testContext, string name)
12 {
13 this.Bundle = Path.Combine(testContext.TestDataFolder, $"{name}.exe");
@@ -28,10 +18,6 @@ namespace WixToolsetTest.BurnE2E
18
19 public string Bundle { get; }
20
31 - public string BundlePdb { get; }
32 -
33 - private WixBundleSymbol BundleSymbol { get; set; }
34 -
21 public string TestGroupName { get; }
22
23 public string TestName { get; }
@@ -146,67 +132,6 @@ namespace WixToolsetTest.BurnE2E
132 return logFile;
133 }
134
149 - private WixBundleSymbol GetBundleSymbol()
150 - {
151 - if (this.BundleSymbol == null)
152 - {
153 - using var wixOutput = WixOutput.Read(this.BundlePdb);
154 - var intermediate = Intermediate.Load(wixOutput);
155 - var section = intermediate.Sections.Single();
156 - this.BundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
157 - }
158 -
159 - return this.BundleSymbol;
160 - }
161 -
162 - public string GetExpectedCachedBundlePath()
163 - {
164 - var bundleSymbol = this.GetBundleSymbol();
165 -
166 - using var policyKey = Registry.LocalMachine.OpenSubKey(FULL_BURN_POLICY_REGISTRY_PATH);
167 - var redirectedCachePath = policyKey?.GetValue("PackageCache") as string;
168 - var cachePath = redirectedCachePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), PACKAGE_CACHE_FOLDER_NAME);
169 - return Path.Combine(cachePath, bundleSymbol.BundleId, Path.GetFileName(this.Bundle));
170 - }
171 -
172 - public string VerifyRegisteredAndInPackageCache()
173 - {
174 - var bundleSymbol = this.GetBundleSymbol();
175 - var bundleId = bundleSymbol.BundleId;
176 - var registrationKeyPath = $"{BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY}\\{bundleId}";
177 -
178 - using var registrationKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
179 - Assert.NotNull(registrationKey);
180 -
181 - var cachePathValue = registrationKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH);
182 - Assert.NotNull(cachePathValue);
183 - var cachePath = Assert.IsType<string>(cachePathValue);
184 - Assert.True(File.Exists(cachePath));
185 -
186 - var expectedCachePath = this.GetExpectedCachedBundlePath();
187 - Assert.Equal(expectedCachePath, cachePath, StringComparer.OrdinalIgnoreCase);
188 -
189 - return cachePath;
190 - }
191 -
192 - public void VerifyUnregisteredAndRemovedFromPackageCache()
193 - {
194 - var cachedBundlePath = this.GetExpectedCachedBundlePath();
195 - this.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
196 - }
197 -
198 - public void VerifyUnregisteredAndRemovedFromPackageCache(string cachedBundlePath)
199 - {
200 - var bundleSymbol = this.GetBundleSymbol();
201 - var bundleId = bundleSymbol.BundleId;
202 - var registrationKeyPath = $"{BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY}\\{bundleId}";
203 -
204 - using var registrationKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
205 - Assert.Null(registrationKey);
206 -
207 - Assert.False(File.Exists(cachedBundlePath));
208 - }
209 -
135 public void Dispose()
136 {
137 string[] args = { "-burn.ignoredependencies=ALL" };
src/WixToolsetTest.BurnE2E/BundleRegistration.cs new
+145
@@ -0,0 +1,145 @@
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 +
8 + public class BundleRegistration
9 + {
10 + public const string BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
11 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH = "BundleCachePath";
12 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE = "BundleAddonCode";
13 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE = "BundleDetectCode";
14 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE = "BundlePatchCode";
15 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE = "BundleUpgradeCode";
16 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME = "DisplayName";
17 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION = "BundleVersion";
18 + public const string BURN_REGISTRATION_REGISTRY_ENGINE_VERSION = "EngineVersion";
19 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY = "BundleProviderKey";
20 + public const string BURN_REGISTRATION_REGISTRY_BUNDLE_TAG = "BundleTag";
21 + public const string REGISTRY_REBOOT_PENDING_FORMAT = "{0}.RebootRequired";
22 + public const string REGISTRY_BUNDLE_INSTALLED = "Installed";
23 + public const string REGISTRY_BUNDLE_DISPLAY_ICON = "DisplayIcon";
24 + public const string REGISTRY_BUNDLE_DISPLAY_VERSION = "DisplayVersion";
25 + public const string REGISTRY_BUNDLE_ESTIMATED_SIZE = "EstimatedSize";
26 + public const string REGISTRY_BUNDLE_PUBLISHER = "Publisher";
27 + public const string REGISTRY_BUNDLE_HELP_LINK = "HelpLink";
28 + public const string REGISTRY_BUNDLE_HELP_TELEPHONE = "HelpTelephone";
29 + public const string REGISTRY_BUNDLE_URL_INFO_ABOUT = "URLInfoAbout";
30 + public const string REGISTRY_BUNDLE_URL_UPDATE_INFO = "URLUpdateInfo";
31 + public const string REGISTRY_BUNDLE_PARENT_DISPLAY_NAME = "ParentDisplayName";
32 + public const string REGISTRY_BUNDLE_PARENT_KEY_NAME = "ParentKeyName";
33 + public const string REGISTRY_BUNDLE_COMMENTS = "Comments";
34 + public const string REGISTRY_BUNDLE_CONTACT = "Contact";
35 + public const string REGISTRY_BUNDLE_NO_MODIFY = "NoModify";
36 + public const string REGISTRY_BUNDLE_MODIFY_PATH = "ModifyPath";
37 + public const string REGISTRY_BUNDLE_NO_ELEVATE_ON_MODIFY = "NoElevateOnModify";
38 + public const string REGISTRY_BUNDLE_NO_REMOVE = "NoRemove";
39 + public const string REGISTRY_BUNDLE_SYSTEM_COMPONENT = "SystemComponent";
40 + public const string REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING = "QuietUninstallString";
41 + public const string REGISTRY_BUNDLE_UNINSTALL_STRING = "UninstallString";
42 + public const string REGISTRY_BUNDLE_RESUME_COMMAND_LINE = "BundleResumeCommandLine";
43 + public const string REGISTRY_BUNDLE_VERSION_MAJOR = "VersionMajor";
44 + public const string REGISTRY_BUNDLE_VERSION_MINOR = "VersionMinor";
45 +
46 + public string[] AddonCodes { get; set; }
47 +
48 + public string CachePath { get; set; }
49 +
50 + public string DisplayName { get; set; }
51 +
52 + public string[] DetectCodes { get; set; }
53 +
54 + public string EngineVersion { get; set; }
55 +
56 + public int? EstimatedSize { get; set; }
57 +
58 + public int? Installed { get; set; }
59 +
60 + public string ModifyPath { get; set; }
61 +
62 + public string[] PatchCodes { get; set; }
63 +
64 + public string ProviderKey { get; set; }
65 +
66 + public string Publisher { get; set; }
67 +
68 + public string QuietUninstallString { get; set; }
69 +
70 + public string QuietUninstallCommand { get; set; }
71 +
72 + public string QuietUninstallCommandArguments { get; set; }
73 +
74 + public string Tag { get; set; }
75 +
76 + public string UninstallCommand { get; set; }
77 +
78 + public string UninstallCommandArguments { get; set; }
79 +
80 + public string UninstallString { get; set; }
81 +
82 + public string[] UpgradeCodes { get; set; }
83 +
84 + public string UrlInfoAbout { get; set; }
85 +
86 + public string UrlUpdateInfo { get; set; }
87 +
88 + public string Version { get; set; }
89 +
90 + public static bool TryGetPerMachineBundleRegistrationById(string bundleId, out BundleRegistration registration)
91 + {
92 + var registrationKeyPath = $"{BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY}\\{bundleId}";
93 + using var registrationKey = Registry.LocalMachine.OpenSubKey(registrationKeyPath);
94 + var success = registrationKey != null;
95 + registration = success ? GetBundleRegistration(registrationKey) : null;
96 + return success;
97 + }
98 +
99 + private static BundleRegistration GetBundleRegistration(RegistryKey idKey)
100 + {
101 + var registration = new BundleRegistration();
102 +
103 + registration.AddonCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE) as string[];
104 + registration.CachePath = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH) as string;
105 + registration.DetectCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE) as string[];
106 + registration.PatchCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE) as string[];
107 + registration.ProviderKey = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY) as string;
108 + registration.Tag = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_TAG) as string;
109 + registration.UpgradeCodes = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE) as string[];
110 + registration.Version = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION) as string;
111 + registration.DisplayName = idKey.GetValue(BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME) as string;
112 + registration.EngineVersion = idKey.GetValue(BURN_REGISTRATION_REGISTRY_ENGINE_VERSION) as string;
113 + registration.EstimatedSize = idKey.GetValue(REGISTRY_BUNDLE_ESTIMATED_SIZE) as int?;
114 + registration.Installed = idKey.GetValue(REGISTRY_BUNDLE_INSTALLED) as int?;
115 + registration.ModifyPath = idKey.GetValue(REGISTRY_BUNDLE_MODIFY_PATH) as string;
116 + registration.Publisher = idKey.GetValue(REGISTRY_BUNDLE_PUBLISHER) as string;
117 + registration.UrlInfoAbout = idKey.GetValue(REGISTRY_BUNDLE_URL_INFO_ABOUT) as string;
118 + registration.UrlUpdateInfo = idKey.GetValue(REGISTRY_BUNDLE_URL_UPDATE_INFO) as string;
119 +
120 + registration.QuietUninstallString = idKey.GetValue(REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING) as string;
121 + if (!String.IsNullOrEmpty(registration.QuietUninstallString))
122 + {
123 + var closeQuote = registration.QuietUninstallString.IndexOf("\"", 1);
124 + if (closeQuote > 0)
125 + {
126 + registration.QuietUninstallCommand = registration.QuietUninstallString.Substring(1, closeQuote - 1).Trim();
127 + registration.QuietUninstallCommandArguments = registration.QuietUninstallString.Substring(closeQuote + 1).Trim();
128 + }
129 + }
130 +
131 + registration.UninstallString = idKey.GetValue(REGISTRY_BUNDLE_UNINSTALL_STRING) as string;
132 + if (!String.IsNullOrEmpty(registration.UninstallString))
133 + {
134 + var closeQuote = registration.UninstallString.IndexOf("\"", 1);
135 + if (closeQuote > 0)
136 + {
137 + registration.UninstallCommand = registration.UninstallString.Substring(1, closeQuote - 1).Trim();
138 + registration.UninstallCommandArguments = registration.UninstallString.Substring(closeQuote + 1).Trim();
139 + }
140 + }
141 +
142 + return registration;
143 + }
144 + }
145 +}
src/WixToolsetTest.BurnE2E/BundleVerifier.cs new
+78
@@ -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 System.IO;
7 + using System.Linq;
8 + using System.Text;
9 + using Microsoft.Win32;
10 + using WixToolset.Data;
11 + using WixToolset.Data.Symbols;
12 + using Xunit;
13 +
14 + public partial class BundleInstaller
15 + {
16 + public const string FULL_BURN_POLICY_REGISTRY_PATH = "SOFTWARE\\WOW6432Node\\Policies\\WiX\\Burn";
17 + public const string PACKAGE_CACHE_FOLDER_NAME = "Package Cache";
18 +
19 + public string BundlePdb { get; }
20 +
21 + private WixBundleSymbol BundleSymbol { get; set; }
22 +
23 + private WixBundleSymbol GetBundleSymbol()
24 + {
25 + if (this.BundleSymbol == null)
26 + {
27 + using var wixOutput = WixOutput.Read(this.BundlePdb);
28 + var intermediate = Intermediate.Load(wixOutput);
29 + var section = intermediate.Sections.Single();
30 + this.BundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
31 + }
32 +
33 + return this.BundleSymbol;
34 + }
35 +
36 + public string GetExpectedCachedBundlePath()
37 + {
38 + var bundleSymbol = this.GetBundleSymbol();
39 +
40 + using var policyKey = Registry.LocalMachine.OpenSubKey(FULL_BURN_POLICY_REGISTRY_PATH);
41 + var redirectedCachePath = policyKey?.GetValue("PackageCache") as string;
42 + var cachePath = redirectedCachePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), PACKAGE_CACHE_FOLDER_NAME);
43 + return Path.Combine(cachePath, bundleSymbol.BundleId, Path.GetFileName(this.Bundle));
44 + }
45 +
46 + public bool TryGetPerMachineRegistration(out BundleRegistration registration)
47 + {
48 + var bundleSymbol = this.GetBundleSymbol();
49 + var bundleId = bundleSymbol.BundleId;
50 + return BundleRegistration.TryGetPerMachineBundleRegistrationById(bundleId, out registration);
51 + }
52 +
53 + public string VerifyRegisteredAndInPackageCache()
54 + {
55 + Assert.True(this.TryGetPerMachineRegistration(out var registration));
56 +
57 + Assert.NotNull(registration.CachePath);
58 + Assert.True(File.Exists(registration.CachePath));
59 +
60 + var expectedCachePath = this.GetExpectedCachedBundlePath();
61 + Assert.Equal(expectedCachePath, registration.CachePath, StringComparer.OrdinalIgnoreCase);
62 +
63 + return registration.CachePath;
64 + }
65 +
66 + public void VerifyUnregisteredAndRemovedFromPackageCache()
67 + {
68 + var cachedBundlePath = this.GetExpectedCachedBundlePath();
69 + this.VerifyUnregisteredAndRemovedFromPackageCache(cachedBundlePath);
70 + }
71 +
72 + public void VerifyUnregisteredAndRemovedFromPackageCache(string cachedBundlePath)
73 + {
74 + Assert.False(this.TryGetPerMachineRegistration(out _));
75 + Assert.False(File.Exists(cachedBundlePath));
76 + }
77 + }
78 +}
src/WixToolsetTest.BurnE2E/BurnE2ETests.cs
+7
@@ -28,6 +28,13 @@ namespace WixToolsetTest.BurnE2E
28 return installer;
29 }
30
31 + protected TestBAController CreateTestBAController()
32 + {
33 + var controller = new TestBAController(this.TestContext);
34 + this.Installers.Enqueue(controller);
35 + return controller;
36 + }
37 +
38 public void Dispose()
39 {
40 while (this.Installers.TryDequeue(out var installer))
src/WixToolsetTest.BurnE2E/FailureTests.cs new
+48
@@ -0,0 +1,48 @@
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 FailureTests : BurnE2ETests
9 + {
10 + public FailureTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
11 +
12 + [Fact]
13 + public void CanCancelMsiPackageVeryEarly()
14 + {
15 + var packageA = this.CreatePackageInstaller("PackageA");
16 + var packageB = this.CreatePackageInstaller("PackageB");
17 + var bundleA = this.CreateBundleInstaller("BundleA");
18 + var testBAController = this.CreateTestBAController();
19 +
20 + // Cancel package B right away.
21 + testBAController.SetPackageCancelExecuteAtProgress("PackageB", 1);
22 +
23 + bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
24 + bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
25 +
26 + packageA.VerifyInstalled(false);
27 + packageB.VerifyInstalled(false);
28 + }
29 +
30 + [Fact]
31 + public void CanCancelMsiPackageVeryLate()
32 + {
33 + var packageA = this.CreatePackageInstaller("PackageA");
34 + var packageB = this.CreatePackageInstaller("PackageB");
35 + var bundleA = this.CreateBundleInstaller("BundleA");
36 + var testBAController = this.CreateTestBAController();
37 +
38 + // Cancel package B at the last moment possible.
39 + testBAController.SetPackageCancelExecuteAtProgress("PackageB", 100);
40 +
41 + bundleA.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
42 + bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
43 +
44 + packageA.VerifyInstalled(false);
45 + packageB.VerifyInstalled(false);
46 + }
47 + }
48 +}
src/WixToolsetTest.BurnE2E/MsiUtilities.cs new
+27
@@ -0,0 +1,27 @@
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 WixToolset.Dtf.WindowsInstaller;
6 +
7 + public class MsiUtilities
8 + {
9 + /// <summary>
10 + /// Return true if it finds the given productcode in system otherwise it returns false
11 + /// </summary>
12 + /// <param name="prodCode"></param>
13 + /// <returns></returns>
14 + public static bool IsProductInstalled(string prodCode)
15 + {
16 + //look in all user's products (both per-machine and per-user)
17 + foreach (ProductInstallation product in ProductInstallation.GetProducts(null, "s-1-1-0", UserContexts.All))
18 + {
19 + if (product.ProductCode == prodCode)
20 + {
21 + return true;
22 + }
23 + }
24 + return false;
25 + }
26 + }
27 +}
src/WixToolsetTest.BurnE2E/PackageInstaller.cs
+2 -8
@@ -6,30 +6,24 @@ namespace WixToolsetTest.BurnE2E
6 using System.IO;
7 using static WixToolsetTest.BurnE2E.MSIExec;
8
9 - public class PackageInstaller : IDisposable
9 + public partial class PackageInstaller : IDisposable
10 {
11 public PackageInstaller(WixTestContext testContext, string name)
12 {
13 this.Package = Path.Combine(testContext.TestDataFolder, $"{name}.msi");
14 + this.PackagePdb = Path.Combine(testContext.TestDataFolder, $"{name}.wixpdb");
15 this.PackageName = name;
16 this.TestContext = testContext;
17 }
18
19 public string Package { get; }
20
20 - private string PackageName { get; }
21 -
21 private WixTestContext TestContext { get; }
22
23 public string TestGroupName => this.TestContext.TestGroupName;
24
25 public string TestName => this.TestContext.TestName;
26
28 - public string GetInstalledFilePath(string filename)
29 - {
30 - return this.TestContext.GetTestInstallFolder(Path.Combine(this.PackageName, filename));
31 - }
32 -
27 /// <summary>
28 /// Installs a .msi file
29 /// </summary>
src/WixToolsetTest.BurnE2E/PackageVerifier.cs new
+50
@@ -0,0 +1,50 @@
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.Linq;
8 + using WixToolset.Data;
9 + using WixToolset.Data.WindowsInstaller;
10 + using WixToolset.Data.WindowsInstaller.Rows;
11 + using Xunit;
12 +
13 + public partial class PackageInstaller
14 + {
15 + private string PackageName { get; }
16 +
17 + public string PackagePdb { get; }
18 +
19 + private WindowsInstallerData WiData { get; set; }
20 +
21 + public string GetInstalledFilePath(string filename)
22 + {
23 + return this.TestContext.GetTestInstallFolder(Path.Combine(this.PackageName, filename));
24 + }
25 +
26 + private WindowsInstallerData GetWindowsInstallerData()
27 + {
28 + if (this.WiData == null)
29 + {
30 + using var wixOutput = WixOutput.Read(this.PackagePdb);
31 + this.WiData = WindowsInstallerData.Load(wixOutput);
32 + }
33 +
34 + return this.WiData;
35 + }
36 +
37 + public string GetProperty(string name)
38 + {
39 + var wiData = this.GetWindowsInstallerData();
40 + var row = wiData.Tables["Property"].Rows.Cast<PropertyRow>().Single(r => r.Property == name);
41 + return row.Value;
42 + }
43 +
44 + public void VerifyInstalled(bool installed)
45 + {
46 + var productCode = this.GetProperty("ProductCode");
47 + Assert.Equal(installed, MsiUtilities.IsProductInstalled(productCode));
48 + }
49 + }
50 +}
src/WixToolsetTest.BurnE2E/TestBAController.cs new
+144
@@ -0,0 +1,144 @@
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 WixToolset.Mba.Core;
8 +
9 + public class TestBAController : IDisposable
10 + {
11 + private const string BaseRegKeyPath = @"Software\WOW6432Node\WiX\Tests";
12 +
13 + public TestBAController(WixTestContext testContext)
14 + {
15 + this.TestGroupName = testContext.TestGroupName;
16 + this.TestBaseRegKeyPath = String.Format(@"{0}\TestBAControl\{1}", BaseRegKeyPath, this.TestGroupName);
17 + }
18 +
19 + private string TestBaseRegKeyPath { get; }
20 +
21 + public string TestGroupName { get; }
22 +
23 + /// <summary>
24 + /// Sets a test value in the registry to communicate with the TestBA.
25 + /// </summary>
26 + /// <param name="name">Name of the value to set.</param>
27 + /// <param name="value">Value to set. If this is null, the value is removed.</param>
28 + public void SetBurnTestValue(string name, string value)
29 + {
30 + using (var testKey = Registry.LocalMachine.CreateSubKey(this.TestBaseRegKeyPath))
31 + {
32 + if (String.IsNullOrEmpty(value))
33 + {
34 + testKey.DeleteValue(name, false);
35 + }
36 + else
37 + {
38 + testKey.SetValue(name, value);
39 + }
40 + }
41 + }
42 +
43 + /// <summary>
44 + /// Slows the cache progress of a package.
45 + /// </summary>
46 + /// <param name="packageId">Package identity.</param>
47 + /// <param name="delay">Sets or removes the delay on a package being cached.</param>
48 + public void SetPackageSlowCache(string packageId, int? delay)
49 + {
50 + this.SetPackageState(packageId, "SlowCache", delay.HasValue ? delay.ToString() : null);
51 + }
52 +
53 + /// <summary>
54 + /// Cancels the cache of a package at a particular progress point.
55 + /// </summary>
56 + /// <param name="packageId">Package identity.</param>
57 + /// <param name="cancelPoint">Sets or removes the cancel progress on a package being cached.</param>
58 + public void SetPackageCancelCacheAtProgress(string packageId, int? cancelPoint)
59 + {
60 + this.SetPackageState(packageId, "CancelCacheAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null);
61 + }
62 +
63 + /// <summary>
64 + /// Slows the execute progress of a package.
65 + /// </summary>
66 + /// <param name="packageId">Package identity.</param>
67 + /// <param name="delay">Sets or removes the delay on a package being executed.</param>
68 + public void SetPackageSlowExecute(string packageId, int? delay)
69 + {
70 + this.SetPackageState(packageId, "SlowExecute", delay.HasValue ? delay.ToString() : null);
71 + }
72 +
73 + /// <summary>
74 + /// Cancels the execute of a package at a particular progress point.
75 + /// </summary>
76 + /// <param name="packageId">Package identity.</param>
77 + /// <param name="cancelPoint">Sets or removes the cancel progress on a package being executed.</param>
78 + public void SetPackageCancelExecuteAtProgress(string packageId, int? cancelPoint)
79 + {
80 + this.SetPackageState(packageId, "CancelExecuteAtProgress", cancelPoint.HasValue ? cancelPoint.ToString() : null);
81 + }
82 +
83 + /// <summary>
84 + /// Sets the requested state for a package that the TestBA will return to the engine during plan.
85 + /// </summary>
86 + /// <param name="packageId">Package identity.</param>
87 + /// <param name="state">State to request.</param>
88 + public void SetPackageRequestedState(string packageId, RequestState state)
89 + {
90 + this.SetPackageState(packageId, "Requested", state.ToString());
91 + }
92 +
93 + /// <summary>
94 + /// Sets the requested state for a package that the TestBA will return to the engine during plan.
95 + /// </summary>
96 + /// <param name="packageId">Package identity.</param>
97 + /// <param name="state">State to request.</param>
98 + public void SetPackageFeatureState(string packageId, string featureId, FeatureState state)
99 + {
100 + this.SetPackageState(packageId, String.Concat(featureId, "Requested"), state.ToString());
101 + }
102 +
103 + /// <summary>
104 + /// Sets the number of times to re-run the Detect phase.
105 + /// </summary>
106 + /// <param name="state">Number of times to run Detect (after the first, normal, Detect).</param>
107 + public void SetRedetectCount(int redetectCount)
108 + {
109 + this.SetPackageState(null, "RedetectCount", redetectCount.ToString());
110 + }
111 +
112 + /// <summary>
113 + /// Resets the state for a package that the TestBA will return to the engine during plan.
114 + /// </summary>
115 + /// <param name="packageId">Package identity.</param>
116 + public void ResetPackageStates(string packageId)
117 + {
118 + var key = String.Format(@"{0}\{1}", this.TestBaseRegKeyPath, packageId ?? String.Empty);
119 + Registry.LocalMachine.DeleteSubKey(key);
120 + }
121 +
122 + private void SetPackageState(string packageId, string name, string value)
123 + {
124 + var key = String.Format(@"{0}\{1}", this.TestBaseRegKeyPath, packageId ?? String.Empty);
125 + using (var packageKey = Registry.LocalMachine.CreateSubKey(key))
126 + {
127 + if (String.IsNullOrEmpty(value))
128 + {
129 + packageKey.DeleteValue(name, false);
130 + }
131 + else
132 + {
133 + packageKey.SetValue(name, value);
134 + }
135 + }
136 + }
137 +
138 + public void Dispose()
139 + {
140 + Registry.LocalMachine.DeleteSubKeyTree($@"{BaseRegKeyPath}\{this.TestGroupName}", false);
141 + Registry.LocalMachine.DeleteSubKeyTree($@"{BaseRegKeyPath}\TestBAControl", false);
142 + }
143 + }
144 +}
src/WixToolsetTest.BurnE2E/WixToolsetTest.BurnE2E.csproj
+1
@@ -17,6 +17,7 @@
17 <PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
18 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.48" />
19 <PackageReference Include="WixToolset.Data" Version="4.0.177" />
20 + <PackageReference Include="WixToolset.Mba.Core" Version="4.0.45" />
21 </ItemGroup>
22
23 <ItemGroup>