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>