Port EnableFeatureSelection tests from v3 repo, add a new one, fix them
Fixes 4616
Sean Hall committed
Aug 22, 2022 at 15:11 UTC
42964da2a12df3b6e7d658a8037f17be003b1947
13 files changed
+288
-5
src/burn/engine/msiengine.cpp
+9
-5
@@ -448,12 +448,15 @@ extern "C" HRESULT MsiEngineDetectPackage(
448
VERUTIL_VERSION* pVersion = NULL;
449
UINT uLcid = 0;
450
BOOL fPerMachine = FALSE;
451
+ BOOL fDetectFeatures = FALSE;
452
453
// detect self by product code
454
// TODO: what to do about MSIINSTALLCONTEXT_USERMANAGED?
455
hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion);
456
if (SUCCEEDED(hr))
457
{
458
+ fDetectFeatures = TRUE;
459
+
460
hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pVersion);
461
ExitOnFailure(hr, "Failed to parse installed version: '%ls' for ProductCode: %ls", sczInstalledVersion, pPackage->Msi.sczProductCode);
462
@@ -661,7 +664,7 @@ extern "C" HRESULT MsiEngineDetectPackage(
664
BURN_MSIFEATURE* pFeature = &pPackage->Msi.rgFeatures[i];
665
666
// Try to detect features state if the product is present on the machine.
664
- if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT <= pPackage->currentState)
667
+ if (fDetectFeatures)
668
{
669
hr = WiuQueryFeatureState(pPackage->Msi.sczProductCode, pFeature->sczId, &installState);
670
ExitOnFailure(hr, "Failed to query feature state.");
@@ -864,8 +867,9 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage(
867
868
if (pPackage->Msi.cFeatures)
869
{
867
- // If the package is present and we're repairing it.
868
- BOOL fRepairingPackage = (BOOTSTRAPPER_PACKAGE_STATE_ABSENT < pPackage->currentState && BOOTSTRAPPER_REQUEST_STATE_REPAIR == pPackage->requested);
870
+ // If the package is present and we're repairing it, or we're doing a minor update.
871
+ BOOL fRepairingPackage = (BOOTSTRAPPER_PACKAGE_STATE_ABSENT < pPackage->currentState && BOOTSTRAPPER_REQUEST_STATE_REPAIR == pPackage->requested) ||
872
+ BOOTSTRAPPER_RELATED_OPERATION_MINOR_UPDATE == pPackage->Msi.operation;
873
874
// plan features
875
for (DWORD i = 0; i < pPackage->Msi.cFeatures; ++i)
@@ -1282,10 +1286,10 @@ extern "C" HRESULT MsiEngineExecutePackage(
1286
hr = ConcatPatchProperty(pCache, pPackage, fRollback, &sczObfuscatedProperties);
1287
ExitOnFailure(hr, "Failed to add patch properties to obfuscated argument string.");
1288
1285
- hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, !pPackage->Msi.cFeatures, &sczProperties);
1289
+ hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, &sczProperties);
1290
ExitOnFailure(hr, "Failed to add action property to argument string.");
1291
1288
- hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, !pPackage->Msi.cFeatures, &sczObfuscatedProperties);
1292
+ hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, &sczObfuscatedProperties);
1293
ExitOnFailure(hr, "Failed to add action property to obfuscated argument string.");
1294
1295
LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->msiPackage.action), sczMsiPath, sczObfuscatedProperties ? sczObfuscatedProperties : L"");
src/test/burn/TestBA/TestBA.cs
+2
@@ -320,6 +320,8 @@ namespace WixToolset.Test.BA
320
{
321
args.State = state;
322
}
323
+
324
+ this.Log("OnPlanMsiFeature() - id: {0}, defaultState: {1}, requestedState: {2}", args.PackageId, args.RecommendedState, args.State);
325
}
326
327
protected override void OnPlanComplete(PlanCompleteEventArgs args)
src/test/burn/TestData/FeatureTests/BundleAv1/BundleA.props
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
+<Project>
3
+ <PropertyGroup>
4
+ <OutputType>Bundle</OutputType>
5
+ <BundleName>BundleA</BundleName>
6
+ <UpgradeCode>{0A6EDDC7-236F-4367-97EF-EFB0F0B478DE}</UpgradeCode>
7
+ </PropertyGroup>
8
+ <ItemGroup>
9
+ <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
10
+ </ItemGroup>
11
+</Project>
src/test/burn/TestData/FeatureTests/BundleAv1/BundleAv1.wixproj
new
+16
@@ -0,0 +1,16 @@
1
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2
+<Project Sdk="WixToolset.Sdk">
3
+ <Import Project="BundleA.props" />
4
+ <PropertyGroup>
5
+ <Version>1.0.0.0</Version>
6
+ </PropertyGroup>
7
+ <ItemGroup>
8
+ <ProjectReference Include="..\PackageAv1\PackageAv1.wixproj" />
9
+ <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
10
+ </ItemGroup>
11
+ <ItemGroup>
12
+ <PackageReference Include="WixToolset.Bal.wixext" />
13
+ <PackageReference Include="WixToolset.NetFx.wixext" />
14
+ <PackageReference Include="WixToolset.Util.wixext" />
15
+ </ItemGroup>
16
+</Project>
\ No newline at end of file
src/test/burn/TestData/FeatureTests/BundleAv1/BundleAv1.wxs
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
+
3
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
4
+ <Fragment>
5
+ <PackageGroup Id="BundlePackages">
6
+ <MsiPackage Id="PackageA" SourceFile="$(var.PackageAv1.TargetPath)" EnableFeatureSelection="yes" />
7
+ </PackageGroup>
8
+ </Fragment>
9
+</Wix>
src/test/burn/TestData/FeatureTests/BundleAv1_0_1/BundleAv1_0_1.wixproj
new
+16
@@ -0,0 +1,16 @@
1
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2
+<Project Sdk="WixToolset.Sdk">
3
+ <Import Project="..\BundleAv1\BundleA.props" />
4
+ <PropertyGroup>
5
+ <Version>1.0.1.0</Version>
6
+ </PropertyGroup>
7
+ <ItemGroup>
8
+ <ProjectReference Include="..\PackageAv1_0_1\PackageAv1_0_1.wixproj" />
9
+ <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
10
+ </ItemGroup>
11
+ <ItemGroup>
12
+ <PackageReference Include="WixToolset.Bal.wixext" />
13
+ <PackageReference Include="WixToolset.NetFx.wixext" />
14
+ <PackageReference Include="WixToolset.Util.wixext" />
15
+ </ItemGroup>
16
+</Project>
\ No newline at end of file
src/test/burn/TestData/FeatureTests/BundleAv1_0_1/BundleAv1_0_1.wxs
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
+
3
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
4
+ <Fragment>
5
+ <PackageGroup Id="BundlePackages">
6
+ <MsiPackage Id="PackageA" Name="PackageAv1.msi" SourceFile="$(var.PackageAv1_0_1.TargetPath)" EnableFeatureSelection="yes" />
7
+ </PackageGroup>
8
+ </Fragment>
9
+</Wix>
src/test/burn/TestData/FeatureTests/PackageAv1/Package.wxs
new
+64
@@ -0,0 +1,64 @@
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
+
5
+<?ifndef Version?>
6
+<?define Version = 1.0.0.0?>
7
+<?endif?>
8
+
9
+<?ifndef ProductCode?>
10
+<?define ProductCode = *?>
11
+<?endif?>
12
+
13
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
14
+ <Package Name="~$(var.TestGroupName) - $(var.PackageName)" Language="1033" Version="$(var.Version)" Manufacturer="WixToolset" UpgradeCode="$(var.UpgradeCode)" Compressed="yes" ProductCode="$(var.ProductCode)">
15
+ <MediaTemplate EmbedCab="yes" />
16
+ <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
17
+
18
+ <PropertyRef Id="TestVersion" />
19
+
20
+ <Feature Id="Complete" Level="1">
21
+ <ComponentRef Id="RegistryComponent"/>
22
+
23
+ <!-- Not installed by default. -->
24
+ <Feature Id="Test" Level="100">
25
+ <ComponentRef Id="FileComponent"/>
26
+ <ComponentRef Id="RegistryComponent2"/>
27
+ </Feature>
28
+ </Feature>
29
+ </Package>
30
+
31
+ <Fragment>
32
+ <StandardDirectory Id="ProgramFiles6432Folder">
33
+ <Directory Id="WixDir" Name="~Test WiX">
34
+ <Directory Id="TestDir" Name="$(var.TestGroupName)">
35
+ <Directory Id="INSTALLFOLDER" Name="$(var.PackageName)" />
36
+ </Directory>
37
+ </Directory>
38
+ </StandardDirectory>
39
+ </Fragment>
40
+
41
+ <Fragment>
42
+ <Component Id="FileComponent" Guid="{771E78AA-850D-4E08-AA6D-3F31E30ED140}" Directory="INSTALLFOLDER">
43
+ <File Source="$(sys.SOURCEFILEPATH)" />
44
+ <File Name="notkeypath.file" Source="$(sys.SOURCEFILEPATH)" />
45
+ </Component>
46
+ </Fragment>
47
+
48
+ <Fragment>
49
+ <Component Id="RegistryComponent" Directory="INSTALLFOLDER">
50
+ <RegistryValue Root="HKLM" Key="Software\WiX\Tests\$(var.TestGroupName)" Name="$(var.PackageName)" Value="!(bind.Property.TestVersion)" Type="string" />
51
+ <Provides Key="WiX.$(var.TestGroupName).A,v1.0" />
52
+ </Component>
53
+ </Fragment>
54
+
55
+ <Fragment>
56
+ <Component Id="RegistryComponent2" Directory="INSTALLFOLDER">
57
+ <RegistryValue Root="HKLM" Key="Software\WiX\Tests\$(var.TestGroupName)" Name="$(var.PackageName)2" Value="!(bind.Property.TestVersion)" Type="string" />
58
+ </Component>
59
+ </Fragment>
60
+
61
+ <Fragment>
62
+ <Property Id="TestVersion" Value="$(var.Version)" />
63
+ </Fragment>
64
+</Wix>
src/test/burn/TestData/FeatureTests/PackageAv1/PackageA.props
new
+7
@@ -0,0 +1,7 @@
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>
3
+ <PropertyGroup>
4
+ <PackageName>PackageA</PackageName>
5
+ <UpgradeCode>{6E3370C1-12DE-4E1C-8AE6-C15113FCE22B}</UpgradeCode>
6
+ </PropertyGroup>
7
+</Project>
\ No newline at end of file
src/test/burn/TestData/FeatureTests/PackageAv1/PackageAv1.props
new
+7
@@ -0,0 +1,7 @@
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>
3
+ <Import Project="PackageA.props" />
4
+ <PropertyGroup>
5
+ <ProductCode>{DD17AA83-3B58-4C97-859A-78F228D0B680}</ProductCode>
6
+ </PropertyGroup>
7
+</Project>
\ No newline at end of file
src/test/burn/TestData/FeatureTests/PackageAv1/PackageAv1.wixproj
new
+4
@@ -0,0 +1,4 @@
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
+ <Import Project="PackageAv1.props" />
4
+</Project>
\ No newline at end of file
src/test/burn/TestData/FeatureTests/PackageAv1_0_1/PackageAv1_0_1.wixproj
new
+10
@@ -0,0 +1,10 @@
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
+ <Import Project="..\PackageAv1\PackageAv1.props" />
4
+ <PropertyGroup>
5
+ <Version>1.0.1.0</Version>
6
+ </PropertyGroup>
7
+ <ItemGroup>
8
+ <Compile Include="..\PackageAv1\Package.wxs" Link="Package.wxs" />
9
+ </ItemGroup>
10
+</Project>
\ No newline at end of file
src/test/burn/WixToolsetTest.BurnE2E/FeatureTests.cs
new
+124
@@ -0,0 +1,124 @@
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 FeatureTests : BurnE2ETests
13
+ {
14
+ public FeatureTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
15
+
16
+ [RuntimeFact]
17
+ public void CanControlFeatureSelectionDuringInstallAndModify()
18
+ {
19
+ var packageA = this.CreatePackageInstaller("PackageAv1");
20
+ var bundleA = this.CreateBundleInstaller("BundleAv1");
21
+ var testBAController = this.CreateTestBAController();
22
+
23
+ // Install the bundle without the optional feature present
24
+ testBAController.SetPackageFeatureState("PackageA", "Complete", FeatureState.Local);
25
+ testBAController.SetPackageFeatureState("PackageA", "Test", FeatureState.Absent);
26
+ bundleA.Install();
27
+ bundleA.VerifyRegisteredAndInPackageCache();
28
+
29
+ string packageSourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
30
+ Assert.False(File.Exists(packageSourceCodeInstalled), String.Concat("Should not have found Package A payload installed at: ", packageSourceCodeInstalled));
31
+ packageA.VerifyTestRegistryValue("PackageA", "1.0.0.0");
32
+
33
+ // Now turn on the feature.
34
+ testBAController.SetPackageFeatureState("PackageA", "Test", FeatureState.Local);
35
+
36
+ bundleA.Modify();
37
+ bundleA.VerifyRegisteredAndInPackageCache();
38
+ Assert.True(File.Exists(packageSourceCodeInstalled), String.Concat("Should have found Package A payload installed at: ", packageSourceCodeInstalled));
39
+
40
+ // Turn the feature back off.
41
+ testBAController.SetPackageFeatureState("PackageA", "Test", FeatureState.Absent);
42
+ bundleA.Modify();
43
+ bundleA.VerifyRegisteredAndInPackageCache();
44
+ Assert.False(File.Exists(packageSourceCodeInstalled), String.Concat("Should have removed Package A payload from: ", packageSourceCodeInstalled));
45
+
46
+ // Uninstall everything.
47
+ testBAController.ResetPackageStates("PackageA");
48
+ bundleA.Uninstall();
49
+ bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
50
+ Assert.False(File.Exists(packageSourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageSourceCodeInstalled));
51
+ packageA.VerifyTestRegistryRootDeleted();
52
+ }
53
+
54
+ [RuntimeFact]
55
+ public void CanControlFeatureSelectionDuringRepair()
56
+ {
57
+ var packageA = this.CreatePackageInstaller("PackageAv1");
58
+ var bundleA = this.CreateBundleInstaller("BundleAv1");
59
+ var testBAController = this.CreateTestBAController();
60
+
61
+ // Install the bundle with the optional feature present
62
+ testBAController.SetPackageFeatureState("PackageA", "Complete", FeatureState.Local);
63
+ testBAController.SetPackageFeatureState("PackageA", "Test", FeatureState.Local);
64
+ bundleA.Install();
65
+ bundleA.VerifyRegisteredAndInPackageCache();
66
+
67
+ string packageSourceCodeInstalled = packageA.GetInstalledFilePath("Package.wxs");
68
+ string packageNotKeyPathFile = packageA.GetInstalledFilePath("notkeypath.file");
69
+
70
+ Assert.True(File.Exists(packageSourceCodeInstalled), String.Concat("Should have found Package A keyfile installed at: ", packageSourceCodeInstalled));
71
+ Assert.True(File.Exists(packageNotKeyPathFile), String.Concat("Should have found Package A non-keyfile installed at: ", packageNotKeyPathFile));
72
+
73
+ // Delete the non-keypath source file.
74
+ File.Delete(packageNotKeyPathFile);
75
+
76
+ // Now repair without repairing the feature to verify the non-keyfile doesn't come back.
77
+ testBAController.SetPackageFeatureState("PackageA", "Test", FeatureState.Unknown);
78
+ bundleA.Repair();
79
+ bundleA.VerifyRegisteredAndInPackageCache();
80
+ Assert.True(File.Exists(packageSourceCodeInstalled), String.Concat("Should have found Package A keyfile installed at: ", packageSourceCodeInstalled));
81
+ Assert.False(File.Exists(packageNotKeyPathFile), String.Concat("Should have not found Package A non-keyfile installed at: ", packageNotKeyPathFile));
82
+
83
+ // Now repair and include the feature this time.
84
+ testBAController.SetPackageFeatureState("PackageA", "Test", FeatureState.Local);
85
+ bundleA.Repair();
86
+ bundleA.VerifyRegisteredAndInPackageCache();
87
+ Assert.True(File.Exists(packageSourceCodeInstalled), String.Concat("Should have found Package A keyfile installed at: ", packageSourceCodeInstalled));
88
+ Assert.True(File.Exists(packageNotKeyPathFile), String.Concat("Should have repaired Package A non-keyfile installed at: ", packageNotKeyPathFile));
89
+
90
+ // Uninstall everything.
91
+ testBAController.ResetPackageStates("PackageA");
92
+ bundleA.Uninstall();
93
+ bundleA.VerifyUnregisteredAndRemovedFromPackageCache();
94
+ Assert.False(File.Exists(packageSourceCodeInstalled), String.Concat("Package A payload should have been removed by uninstall from: ", packageSourceCodeInstalled));
95
+ packageA.VerifyTestRegistryRootDeleted();
96
+ }
97
+
98
+ [RuntimeFact]
99
+ public void CanControlFeatureSelectionDuringMinorUpgrade()
100
+ {
101
+ var packageAv1 = this.CreatePackageInstaller("PackageAv1");
102
+ var packageAv1_0_1 = this.CreatePackageInstaller("PackageAv1_0_1");
103
+ var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
104
+ var bundleAv1_0_1 = this.CreateBundleInstaller("BundleAv1_0_1");
105
+ var testBAController = this.CreateTestBAController();
106
+
107
+ // Install v1 with the optional feature turned on.
108
+ testBAController.SetPackageFeatureState("PackageA", "Complete", FeatureState.Local);
109
+ testBAController.SetPackageFeatureState("PackageA", "Test", FeatureState.Local);
110
+ bundleAv1.Install();
111
+ bundleAv1.VerifyRegisteredAndInPackageCache();
112
+
113
+ packageAv1.VerifyInstalledWithVersion(true);
114
+ packageAv1.VerifyTestRegistryValue("PackageA", "1.0.0.0");
115
+
116
+ // Install v1.0.1 with the optional feature still turned on.
117
+ bundleAv1_0_1.Install();
118
+ bundleAv1_0_1.VerifyRegisteredAndInPackageCache();
119
+
120
+ packageAv1_0_1.VerifyInstalledWithVersion(true);
121
+ packageAv1_0_1.VerifyTestRegistryValue("PackageA", "1.0.1.0");
122
+ }
123
+ }
124
+}