diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-06-24 12:28:27 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-06-27 11:14:21 -0500 |
| commit | eb53852d7ae6838e54525eb57df1d8ce8a722f9b (patch) | |
| tree | 7fa05bd6df1bce2e20d87c5fbacc1c658dc000aa /src/test | |
| parent | 6ee12a64cb75097a238e60d4fd0ea542e8312214 (diff) | |
| download | wix-eb53852d7ae6838e54525eb57df1d8ce8a722f9b.tar.gz wix-eb53852d7ae6838e54525eb57df1d8ce8a722f9b.tar.bz2 wix-eb53852d7ae6838e54525eb57df1d8ce8a722f9b.zip | |
Add longPathAware to Burn manifest to support long paths.
Fixes 3455
Diffstat (limited to 'src/test')
12 files changed, 439 insertions, 7 deletions
diff --git a/src/test/burn/Directory.wixproj.targets b/src/test/burn/Directory.wixproj.targets index 17a46e2a..4037e865 100644 --- a/src/test/burn/Directory.wixproj.targets +++ b/src/test/burn/Directory.wixproj.targets | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | <WebServerBaseUrl Condition=" '$(WebServerBaseUrl)' == '' ">http://localhost:9999/e2e/</WebServerBaseUrl> | 7 | <WebServerBaseUrl Condition=" '$(WebServerBaseUrl)' == '' ">http://localhost:9999/e2e/</WebServerBaseUrl> |
| 8 | <DefineConstants>TestGroupName=$(TestGroupName);PackageName=$(PackageName);BundleName=$(BundleName);WebServerBaseUrl=$(WebServerBaseUrl);$(DefineConstants)</DefineConstants> | 8 | <DefineConstants>TestGroupName=$(TestGroupName);PackageName=$(PackageName);BundleName=$(BundleName);WebServerBaseUrl=$(WebServerBaseUrl);$(DefineConstants)</DefineConstants> |
| 9 | <DefineConstants Condition=" '$(BA)' != '' ">BA=$(BA);$(DefineConstants)</DefineConstants> | 9 | <DefineConstants Condition=" '$(BA)' != '' ">BA=$(BA);$(DefineConstants)</DefineConstants> |
| 10 | <DefineConstants Condition=" '$(BundleLogDirectory)' != '' ">BundleLogDirectory=$(BundleLogDirectory);$(DefineConstants)</DefineConstants> | ||
| 10 | <DefineConstants Condition=" '$(CabPrefix)' != '' ">CabPrefix=$(CabPrefix);$(DefineConstants)</DefineConstants> | 11 | <DefineConstants Condition=" '$(CabPrefix)' != '' ">CabPrefix=$(CabPrefix);$(DefineConstants)</DefineConstants> |
| 11 | <DefineConstants Condition=" '$(IncludeSoftwareTag)' == 'true' ">SoftwareTag=1;$(DefineConstants)</DefineConstants> | 12 | <DefineConstants Condition=" '$(IncludeSoftwareTag)' == 'true' ">SoftwareTag=1;$(DefineConstants)</DefineConstants> |
| 12 | <DefineConstants Condition=" '$(ProductCode)' != '' ">ProductCode=$(ProductCode);$(DefineConstants)</DefineConstants> | 13 | <DefineConstants Condition=" '$(ProductCode)' != '' ">ProductCode=$(ProductCode);$(DefineConstants)</DefineConstants> |
diff --git a/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wixproj b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wixproj new file mode 100644 index 00000000..3686200c --- /dev/null +++ b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wixproj | |||
| @@ -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>{EFCF768F-1B06-4B68-9DE0-9244F8212D31}</UpgradeCode> | ||
| 6 | <BundleLogDirectory>[LocalAppDataFolder]Temp</BundleLogDirectory> | ||
| 7 | </PropertyGroup> | ||
| 8 | <ItemGroup> | ||
| 9 | <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" /> | ||
| 10 | </ItemGroup> | ||
| 11 | <ItemGroup> | ||
| 12 | <ProjectReference Include="..\PackageA\PackageA.wixproj" /> | ||
| 13 | <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" /> | ||
| 14 | </ItemGroup> | ||
| 15 | <ItemGroup> | ||
| 16 | <PackageReference Include="WixToolset.Bal.wixext" /> | ||
| 17 | <PackageReference Include="WixToolset.NetFx.wixext" /> | ||
| 18 | </ItemGroup> | ||
| 19 | </Project> \ No newline at end of file | ||
diff --git a/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wxs b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wxs new file mode 100644 index 00000000..e3872eb1 --- /dev/null +++ b/src/test/burn/TestData/LongPathTests/NonCompressedBundle/NonCompressedBundle.wxs | |||
| @@ -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 | |||
| 3 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 5 | <Fragment> | ||
| 6 | <PackageGroup Id="BundlePackages"> | ||
| 7 | <MsiPackage Compressed="no" Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" /> | ||
| 8 | </PackageGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/test/burn/TestData/LongPathTests/PackageA/PackageA.wixproj b/src/test/burn/TestData/LongPathTests/PackageA/PackageA.wixproj new file mode 100644 index 00000000..798452e7 --- /dev/null +++ b/src/test/burn/TestData/LongPathTests/PackageA/PackageA.wixproj | |||
| @@ -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 | <PropertyGroup> | ||
| 4 | <CabPrefix>a</CabPrefix> | ||
| 5 | <UpgradeCode>{4DC05A2A-382D-4E7D-B6DA-163908396373}</UpgradeCode> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | </Project> \ No newline at end of file | ||
diff --git a/src/test/burn/TestData/Templates/Bundle.wxs b/src/test/burn/TestData/Templates/Bundle.wxs index b211d9c3..612e67f5 100644 --- a/src/test/burn/TestData/Templates/Bundle.wxs +++ b/src/test/burn/TestData/Templates/Bundle.wxs | |||
| @@ -3,10 +3,13 @@ | |||
| 3 | <?ifndef Version?> | 3 | <?ifndef Version?> |
| 4 | <?define Version = 1.0.0.0?> | 4 | <?define Version = 1.0.0.0?> |
| 5 | <?endif?> | 5 | <?endif?> |
| 6 | <?ifndef BundleLogDirectory?> | ||
| 7 | <?define BundleLogDirectory = .?> | ||
| 8 | <?endif?> | ||
| 6 | 9 | ||
| 7 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal"> | 10 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal"> |
| 8 | <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="yes"> | 11 | <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="yes"> |
| 9 | <Log Prefix="~$(var.TestGroupName)_$(var.BundleName)" /> | 12 | <Log Prefix="$(var.BundleLogDirectory)\~$(var.TestGroupName)_$(var.BundleName)" /> |
| 10 | 13 | ||
| 11 | <Variable Name="TestGroupName" Value="$(var.TestGroupName)" /> | 14 | <Variable Name="TestGroupName" Value="$(var.TestGroupName)" /> |
| 12 | 15 | ||
diff --git a/src/test/burn/TestExe/Task.cs b/src/test/burn/TestExe/Task.cs index 59f774fb..0d283c6c 100644 --- a/src/test/burn/TestExe/Task.cs +++ b/src/test/burn/TestExe/Task.cs | |||
| @@ -2,8 +2,10 @@ | |||
| 2 | 2 | ||
| 3 | using System; | 3 | using System; |
| 4 | using System.Collections.Generic; | 4 | using System.Collections.Generic; |
| 5 | using System.ComponentModel; | ||
| 5 | using System.Diagnostics; | 6 | using System.Diagnostics; |
| 6 | using System.IO; | 7 | using System.IO; |
| 8 | using System.Runtime.InteropServices; | ||
| 7 | using Microsoft.Win32; | 9 | using Microsoft.Win32; |
| 8 | 10 | ||
| 9 | namespace TestExe | 11 | namespace TestExe |
| @@ -151,6 +153,67 @@ namespace TestExe | |||
| 151 | } | 153 | } |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 156 | public class DeleteManifestsTask : Task | ||
| 157 | { | ||
| 158 | public DeleteManifestsTask(string Data) : base(Data) { } | ||
| 159 | |||
| 160 | public override void RunTask() | ||
| 161 | { | ||
| 162 | string filePath = System.Environment.ExpandEnvironmentVariables(this.data); | ||
| 163 | IntPtr type = new IntPtr(24); //RT_MANIFEST | ||
| 164 | IntPtr name = new IntPtr(1); //CREATEPROCESS_MANIFEST_RESOURCE_ID | ||
| 165 | DeleteResource(filePath, type, name, 1033); | ||
| 166 | } | ||
| 167 | |||
| 168 | private static void DeleteResource(string filePath, IntPtr type, IntPtr name, ushort language, bool throwOnError = false) | ||
| 169 | { | ||
| 170 | bool discard = true; | ||
| 171 | IntPtr handle = BeginUpdateResourceW(filePath, false); | ||
| 172 | try | ||
| 173 | { | ||
| 174 | if (handle == IntPtr.Zero) | ||
| 175 | { | ||
| 176 | throw new Win32Exception(); | ||
| 177 | } | ||
| 178 | |||
| 179 | if (!UpdateResourceW(handle, type, name, language, IntPtr.Zero, 0)) | ||
| 180 | { | ||
| 181 | throw new Win32Exception(); | ||
| 182 | } | ||
| 183 | |||
| 184 | discard = false; | ||
| 185 | } | ||
| 186 | catch | ||
| 187 | { | ||
| 188 | if (throwOnError) | ||
| 189 | { | ||
| 190 | throw; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | finally | ||
| 194 | { | ||
| 195 | if (handle != IntPtr.Zero) | ||
| 196 | { | ||
| 197 | if (!EndUpdateResourceW(handle, discard) && throwOnError) | ||
| 198 | { | ||
| 199 | throw new Win32Exception(); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 206 | private extern static IntPtr BeginUpdateResourceW(string fileName, [MarshalAs(UnmanagedType.Bool)] bool deleteExistingResources); | ||
| 207 | |||
| 208 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 209 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 210 | private extern static bool UpdateResourceW(IntPtr hUpdate, IntPtr type, IntPtr name, ushort language, IntPtr pData, uint cb); | ||
| 211 | |||
| 212 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 213 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 214 | private extern static bool EndUpdateResourceW(IntPtr hUpdate, [MarshalAs(UnmanagedType.Bool)] bool discard); | ||
| 215 | } | ||
| 216 | |||
| 154 | public class TaskParser | 217 | public class TaskParser |
| 155 | { | 218 | { |
| 156 | 219 | ||
| @@ -197,6 +260,10 @@ namespace TestExe | |||
| 197 | t = new FileExistsTask(args[i + 1]); | 260 | t = new FileExistsTask(args[i + 1]); |
| 198 | tasks.Add(t); | 261 | tasks.Add(t); |
| 199 | break; | 262 | break; |
| 263 | case "/dm": | ||
| 264 | t = new DeleteManifestsTask(args[i + 1]); | ||
| 265 | tasks.Add(t); | ||
| 266 | break; | ||
| 200 | #if NET35 | 267 | #if NET35 |
| 201 | case "/pinfo": | 268 | case "/pinfo": |
| 202 | t = new ProcessInfoTask(args[i + 1]); | 269 | t = new ProcessInfoTask(args[i + 1]); |
diff --git a/src/test/burn/WixTestTools/BundleInstaller.cs b/src/test/burn/WixTestTools/BundleInstaller.cs index 5551d3c0..0f2cfa8f 100644 --- a/src/test/burn/WixTestTools/BundleInstaller.cs +++ b/src/test/burn/WixTestTools/BundleInstaller.cs | |||
| @@ -28,6 +28,8 @@ namespace WixTestTools | |||
| 28 | 28 | ||
| 29 | public int? AlternateExitCode { get; set; } | 29 | public int? AlternateExitCode { get; set; } |
| 30 | 30 | ||
| 31 | public string LogDirectory { get; set; } | ||
| 32 | |||
| 31 | public int? LastExitCode { get; set; } | 33 | public int? LastExitCode { get; set; } |
| 32 | 34 | ||
| 33 | /// <summary> | 35 | /// <summary> |
| @@ -194,7 +196,7 @@ namespace WixTestTools | |||
| 194 | sb.Append(" -quiet"); | 196 | sb.Append(" -quiet"); |
| 195 | 197 | ||
| 196 | // Generate the log file name. | 198 | // Generate the log file name. |
| 197 | string logFile = Path.Combine(Path.GetTempPath(), String.Format("{0}_{1}_{2:yyyyMMddhhmmss}_{4}_{3}.log", this.TestGroupName, this.TestName, DateTime.UtcNow, Path.GetFileNameWithoutExtension(this.Bundle), mode)); | 199 | string logFile = Path.Combine(this.LogDirectory ?? Path.GetTempPath(), String.Format("{0}_{1}_{2:yyyyMMddhhmmss}_{4}_{3}.log", this.TestGroupName, this.TestName, DateTime.UtcNow, Path.GetFileNameWithoutExtension(this.Bundle), mode)); |
| 198 | sb.AppendFormat(" -log \"{0}\"", logFile); | 200 | sb.AppendFormat(" -log \"{0}\"", logFile); |
| 199 | 201 | ||
| 200 | // Set operation. | 202 | // Set operation. |
diff --git a/src/test/burn/WixTestTools/MSIExec.cs b/src/test/burn/WixTestTools/MSIExec.cs index a10a48d6..5f57da7b 100644 --- a/src/test/burn/WixTestTools/MSIExec.cs +++ b/src/test/burn/WixTestTools/MSIExec.cs | |||
| @@ -110,7 +110,7 @@ namespace WixTestTools | |||
| 110 | this.NoRestart = true; | 110 | this.NoRestart = true; |
| 111 | this.ForceRestart = false; | 111 | this.ForceRestart = false; |
| 112 | this.PromptRestart = false; | 112 | this.PromptRestart = false; |
| 113 | this.LogFile = string.Empty; | 113 | this.LogFile = String.Empty; |
| 114 | this.LoggingOptions = MSIExecLoggingOptions.VOICEWARMUP; | 114 | this.LoggingOptions = MSIExecLoggingOptions.VOICEWARMUP; |
| 115 | this.OtherArguments = String.Empty; | 115 | this.OtherArguments = String.Empty; |
| 116 | } | 116 | } |
| @@ -230,14 +230,14 @@ namespace WixTestTools | |||
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | // logfile and logging options | 232 | // logfile and logging options |
| 233 | if (0 != loggingOptionsString.Length || !string.IsNullOrEmpty(this.LogFile)) | 233 | if (0 != loggingOptionsString.Length || !String.IsNullOrEmpty(this.LogFile)) |
| 234 | { | 234 | { |
| 235 | arguments.Append(" /l"); | 235 | arguments.Append(" /l"); |
| 236 | if (0 != loggingOptionsString.Length) | 236 | if (0 != loggingOptionsString.Length) |
| 237 | { | 237 | { |
| 238 | arguments.AppendFormat("{0} ", loggingOptionsString); | 238 | arguments.AppendFormat("{0} ", loggingOptionsString); |
| 239 | } | 239 | } |
| 240 | if (!string.IsNullOrEmpty(this.LogFile)) | 240 | if (!String.IsNullOrEmpty(this.LogFile)) |
| 241 | { | 241 | { |
| 242 | arguments.AppendFormat(" \"{0}\" ", this.LogFile); | 242 | arguments.AppendFormat(" \"{0}\" ", this.LogFile); |
| 243 | } | 243 | } |
| @@ -268,7 +268,7 @@ namespace WixTestTools | |||
| 268 | }; | 268 | }; |
| 269 | 269 | ||
| 270 | // product | 270 | // product |
| 271 | if (!string.IsNullOrEmpty(this.Product)) | 271 | if (!String.IsNullOrEmpty(this.Product)) |
| 272 | { | 272 | { |
| 273 | arguments.AppendFormat(" \"{0}\" ", this.Product); | 273 | arguments.AppendFormat(" \"{0}\" ", this.Product); |
| 274 | } | 274 | } |
| @@ -311,6 +311,12 @@ namespace WixTestTools | |||
| 311 | ERROR_CALL_NOT_IMPLEMENTED = 120, | 311 | ERROR_CALL_NOT_IMPLEMENTED = 120, |
| 312 | 312 | ||
| 313 | /// <summary> | 313 | /// <summary> |
| 314 | /// ERROR_FILENAME_EXCED_RANGE 206 | ||
| 315 | /// The filename or extension is too long. | ||
| 316 | /// </summary> | ||
| 317 | ERROR_FILENAME_EXCED_RANGE = 206, | ||
| 318 | |||
| 319 | /// <summary> | ||
| 314 | /// ERROR_APPHELP_BLOCK 1259 | 320 | /// ERROR_APPHELP_BLOCK 1259 |
| 315 | /// If Windows Installer determines a product may be incompatible with the current operating system, | 321 | /// If Windows Installer determines a product may be incompatible with the current operating system, |
| 316 | /// it displays a dialog box informing the user and asking whether to try to install anyway. | 322 | /// it displays a dialog box informing the user and asking whether to try to install anyway. |
diff --git a/src/test/burn/WixTestTools/TestTool.cs b/src/test/burn/WixTestTools/TestTool.cs index eb77c75b..79e7004c 100644 --- a/src/test/burn/WixTestTools/TestTool.cs +++ b/src/test/burn/WixTestTools/TestTool.cs | |||
| @@ -229,7 +229,7 @@ namespace WixTestTools | |||
| 229 | returnValue.AppendLine("Tool run result:"); | 229 | returnValue.AppendLine("Tool run result:"); |
| 230 | returnValue.AppendLine("----------------"); | 230 | returnValue.AppendLine("----------------"); |
| 231 | returnValue.AppendLine("Command:"); | 231 | returnValue.AppendLine("Command:"); |
| 232 | returnValue.AppendLine($"\"{result.StartInfo.FileName}\" {result.StartInfo.Arguments}"); | 232 | returnValue.AppendLine($"\"{result.FileName}\" {result.Arguments}"); |
| 233 | returnValue.AppendLine(); | 233 | returnValue.AppendLine(); |
| 234 | returnValue.AppendLine("Standard Output:"); | 234 | returnValue.AppendLine("Standard Output:"); |
| 235 | foreach (var line in result.StandardOutput ?? new string[0]) | 235 | foreach (var line in result.StandardOutput ?? new string[0]) |
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs new file mode 100644 index 00000000..ba793d7a --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs | |||
| @@ -0,0 +1,298 @@ | |||
| 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.ComponentModel; | ||
| 7 | using System.IO; | ||
| 8 | using System.Runtime.InteropServices; | ||
| 9 | using Microsoft.Win32; | ||
| 10 | using WixBuildTools.TestSupport; | ||
| 11 | using WixTestTools; | ||
| 12 | using WixToolset.Mba.Core; | ||
| 13 | using Xunit; | ||
| 14 | using Xunit.Abstractions; | ||
| 15 | |||
| 16 | public class LongPathTests : BurnE2ETests | ||
| 17 | { | ||
| 18 | public LongPathTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | ||
| 19 | |||
| 20 | [RuntimeFact] | ||
| 21 | public void CanInstallAndUninstallSimpleBundle_x86_wixstdba() | ||
| 22 | { | ||
| 23 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleA"); | ||
| 24 | } | ||
| 25 | |||
| 26 | [RuntimeFact] | ||
| 27 | public void CanInstallAndUninstallSimpleBundle_x86_testba() | ||
| 28 | { | ||
| 29 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleB"); | ||
| 30 | } | ||
| 31 | |||
| 32 | [RuntimeFact] | ||
| 33 | public void CanInstallAndUninstallSimpleBundle_x86_dnctestba() | ||
| 34 | { | ||
| 35 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleC"); | ||
| 36 | } | ||
| 37 | |||
| 38 | [RuntimeFact] | ||
| 39 | public void CanInstallAndUninstallSimpleBundle_x86_wixba() | ||
| 40 | { | ||
| 41 | this.CanInstallAndUninstallSimpleBundle("PackageA", "BundleD"); | ||
| 42 | } | ||
| 43 | |||
| 44 | [RuntimeFact] | ||
| 45 | public void CanInstallAndUninstallSimpleBundle_x64_wixstdba() | ||
| 46 | { | ||
| 47 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleA_x64"); | ||
| 48 | } | ||
| 49 | |||
| 50 | [RuntimeFact] | ||
| 51 | public void CanInstallAndUninstallSimplePerUserBundle_x64_wixstdba() | ||
| 52 | { | ||
| 53 | this.CanInstallAndUninstallSimpleBundle("PackageApu_x64", "BundleApu_x64", "PackagePerUser.wxs", unchecked((int)0xc0000005)); | ||
| 54 | } | ||
| 55 | |||
| 56 | [RuntimeFact] | ||
| 57 | public void CanInstallAndUninstallSimpleBundle_x64_testba() | ||
| 58 | { | ||
| 59 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleB_x64"); | ||
| 60 | } | ||
| 61 | |||
| 62 | [RuntimeFact] | ||
| 63 | public void CanInstallAndUninstallSimpleBundle_x64_dnctestba() | ||
| 64 | { | ||
| 65 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleC_x64"); | ||
| 66 | } | ||
| 67 | |||
| 68 | [RuntimeFact] | ||
| 69 | public void CanInstallAndUninstallSimpleBundle_x64_dncwixba() | ||
| 70 | { | ||
| 71 | this.CanInstallAndUninstallSimpleBundle("PackageA_x64", "BundleD_x64"); | ||
| 72 | } | ||
| 73 | |||
| 74 | private void CanInstallAndUninstallSimpleBundle(string packageName, string bundleName, string fileName = "Package.wxs", int? alternateExitCode = null) | ||
| 75 | { | ||
| 76 | var package = this.CreatePackageInstaller(Path.Combine("..", "BasicFunctionalityTests", packageName)); | ||
| 77 | |||
| 78 | var bundle = this.CreateBundleInstaller(Path.Combine("..", "BasicFunctionalityTests", bundleName)); | ||
| 79 | bundle.AlternateExitCode = alternateExitCode; | ||
| 80 | |||
| 81 | using var dfs = new DisposableFileSystem(); | ||
| 82 | var baseFolder = GetLongPath(dfs.GetFolder()); | ||
| 83 | |||
| 84 | var packageSourceCodeInstalled = package.GetInstalledFilePath(fileName); | ||
| 85 | |||
| 86 | // Source file should *not* be installed | ||
| 87 | Assert.False(File.Exists(packageSourceCodeInstalled), $"{packageName} payload should not be there on test start: {packageSourceCodeInstalled}"); | ||
| 88 | |||
| 89 | var bundleFileInfo = new FileInfo(bundle.Bundle); | ||
| 90 | var bundleCopiedPath = Path.Combine(baseFolder, bundleFileInfo.Name); | ||
| 91 | bundleFileInfo.CopyTo(bundleCopiedPath); | ||
| 92 | |||
| 93 | bundle.Install(bundleCopiedPath); | ||
| 94 | bundle.VerifyRegisteredAndInPackageCache(); | ||
| 95 | |||
| 96 | // Source file should be installed | ||
| 97 | Assert.True(File.Exists(packageSourceCodeInstalled), $"Should have found {packageName} payload installed at: {packageSourceCodeInstalled}"); | ||
| 98 | |||
| 99 | if (alternateExitCode == bundle.LastExitCode) | ||
| 100 | { | ||
| 101 | WixAssert.Skip($"Install exited with {bundle.LastExitCode}"); | ||
| 102 | } | ||
| 103 | |||
| 104 | bundle.Uninstall(bundleCopiedPath); | ||
| 105 | |||
| 106 | // Source file should *not* be installed | ||
| 107 | Assert.False(File.Exists(packageSourceCodeInstalled), $"{packageName} payload should have been removed by uninstall from: {packageSourceCodeInstalled}"); | ||
| 108 | |||
| 109 | bundle.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 110 | |||
| 111 | if (alternateExitCode == bundle.LastExitCode) | ||
| 112 | { | ||
| 113 | WixAssert.Skip($"Uninstall exited with {bundle.LastExitCode}"); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | [RuntimeFact] | ||
| 118 | public void CanLayoutNonCompressedBundleToLongPath() | ||
| 119 | { | ||
| 120 | var nonCompressedBundle = this.CreateBundleInstaller("NonCompressedBundle"); | ||
| 121 | var testBAController = this.CreateTestBAController(); | ||
| 122 | |||
| 123 | testBAController.SetPackageRequestedState("NetFx48Web", RequestState.None); | ||
| 124 | |||
| 125 | using var dfs = new DisposableFileSystem(); | ||
| 126 | var layoutDirectory = GetLongPath(dfs.GetFolder()); | ||
| 127 | |||
| 128 | nonCompressedBundle.Layout(layoutDirectory); | ||
| 129 | nonCompressedBundle.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 130 | |||
| 131 | Assert.True(File.Exists(Path.Combine(layoutDirectory, "NonCompressedBundle.exe"))); | ||
| 132 | Assert.True(File.Exists(Path.Combine(layoutDirectory, "PackageA.msi"))); | ||
| 133 | Assert.True(File.Exists(Path.Combine(layoutDirectory, "1a.cab"))); | ||
| 134 | Assert.False(File.Exists(Path.Combine(layoutDirectory, @"redist\ndp48-web.exe"))); | ||
| 135 | } | ||
| 136 | |||
| 137 | [RuntimeFact] | ||
| 138 | public void CanInstallNonCompressedBundleWithLongTempPath() | ||
| 139 | { | ||
| 140 | this.InstallNonCompressedBundle(longTemp: true, useOriginalTempForLog: true); | ||
| 141 | } | ||
| 142 | |||
| 143 | [RuntimeFact] | ||
| 144 | public void CannotInstallNonCompressedBundleWithLongPackageCachePath() | ||
| 145 | { | ||
| 146 | var installLogPath = this.InstallNonCompressedBundle((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, longPackageCache: true); | ||
| 147 | Assert.True(LogVerifier.MessageInLogFile(installLogPath, @"Error 0x80070643: Failed to install MSI package")); | ||
| 148 | } | ||
| 149 | |||
| 150 | [RuntimeFact] | ||
| 151 | public void CannotInstallNonCompressedBundleWithLongWorkingPath() | ||
| 152 | { | ||
| 153 | var installLogPath = this.InstallNonCompressedBundle((int)MSIExec.MSIExecReturnCode.ERROR_FILENAME_EXCED_RANGE | unchecked((int)0x80070000), longWorkingPath: true); | ||
| 154 | Assert.True(LogVerifier.MessageInLogFile(installLogPath, @"Error 0x800700ce: Failed to load BA DLL")); | ||
| 155 | } | ||
| 156 | |||
| 157 | public string InstallNonCompressedBundle(int expectedExitCode = 0, bool longTemp = false, bool useOriginalTempForLog = false, bool longWorkingPath = false, bool longPackageCache = false, int? alternateExitCode = null) | ||
| 158 | { | ||
| 159 | var deletePolicyKey = false; | ||
| 160 | string originalEngineWorkingDirectoryValue = null; | ||
| 161 | string originalPackageCacheValue = null; | ||
| 162 | var originalTemp = Environment.GetEnvironmentVariable("TMP"); | ||
| 163 | var packageA = this.CreatePackageInstaller("PackageA"); | ||
| 164 | var nonCompressedBundle = this.CreateBundleInstaller("NonCompressedBundle"); | ||
| 165 | var policyPath = nonCompressedBundle.GetFullBurnPolicyRegistryPath(); | ||
| 166 | string installLogPath = null; | ||
| 167 | |||
| 168 | try | ||
| 169 | { | ||
| 170 | using var dfs = new DisposableFileSystem(); | ||
| 171 | var originalBaseFolder = dfs.GetFolder(); | ||
| 172 | var baseFolder = GetLongPath(originalBaseFolder); | ||
| 173 | var sourceFolder = Path.Combine(baseFolder, "source"); | ||
| 174 | var workingFolder = Path.Combine(baseFolder, "working"); | ||
| 175 | var tempFolder = Path.Combine(originalBaseFolder, new string('d', 260 - originalBaseFolder.Length - 2)); | ||
| 176 | var packageCacheFolder = Path.Combine(baseFolder, "package cache"); | ||
| 177 | |||
| 178 | var copyResult = TestDataFolderFileSystem.RobocopyFolder(this.TestContext.TestDataFolder, sourceFolder); | ||
| 179 | Assert.True(copyResult.ExitCode >= 0 && copyResult.ExitCode < 8, $"Exit code: {copyResult.ExitCode}\r\nOutput: {String.Join("\r\n", copyResult.StandardOutput)}\r\nError: {String.Join("\r\n", copyResult.StandardError)}"); | ||
| 180 | |||
| 181 | var bundleFileInfo = new FileInfo(nonCompressedBundle.Bundle); | ||
| 182 | var bundleCopiedPath = Path.Combine(sourceFolder, bundleFileInfo.Name); | ||
| 183 | |||
| 184 | var policyKey = Registry.LocalMachine.OpenSubKey(policyPath, writable: true); | ||
| 185 | if (policyKey == null) | ||
| 186 | { | ||
| 187 | policyKey = Registry.LocalMachine.CreateSubKey(policyPath, writable: true); | ||
| 188 | deletePolicyKey = true; | ||
| 189 | } | ||
| 190 | |||
| 191 | using (policyKey) | ||
| 192 | { | ||
| 193 | originalEngineWorkingDirectoryValue = policyKey.GetValue("EngineWorkingDirectory") as string; | ||
| 194 | originalPackageCacheValue = policyKey.GetValue("PackageCache") as string; | ||
| 195 | |||
| 196 | if (longWorkingPath) | ||
| 197 | { | ||
| 198 | policyKey.SetValue("EngineWorkingDirectory", workingFolder); | ||
| 199 | } | ||
| 200 | |||
| 201 | if (longPackageCache) | ||
| 202 | { | ||
| 203 | policyKey.SetValue("PackageCache", packageCacheFolder); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | if (longTemp) | ||
| 208 | { | ||
| 209 | Environment.SetEnvironmentVariable("TMP", tempFolder); | ||
| 210 | |||
| 211 | if (useOriginalTempForLog) | ||
| 212 | { | ||
| 213 | nonCompressedBundle.LogDirectory = originalTemp; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | try | ||
| 218 | { | ||
| 219 | nonCompressedBundle.AlternateExitCode = alternateExitCode; | ||
| 220 | installLogPath = nonCompressedBundle.Install(bundleCopiedPath, expectedExitCode); | ||
| 221 | |||
| 222 | if (alternateExitCode == nonCompressedBundle.LastExitCode) | ||
| 223 | { | ||
| 224 | WixAssert.Skip($"Install exited with {nonCompressedBundle.LastExitCode}"); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | finally | ||
| 228 | { | ||
| 229 | TestDataFolderFileSystem.RobocopyFolder(tempFolder, originalTemp); | ||
| 230 | } | ||
| 231 | |||
| 232 | installLogPath = Path.Combine(originalTemp, Path.GetFileName(installLogPath)); | ||
| 233 | |||
| 234 | if (expectedExitCode == 0) | ||
| 235 | { | ||
| 236 | var registration = nonCompressedBundle.VerifyRegisteredAndInPackageCache(); | ||
| 237 | packageA.VerifyInstalled(true); | ||
| 238 | |||
| 239 | nonCompressedBundle.Uninstall(registration.CachePath); | ||
| 240 | |||
| 241 | if (alternateExitCode == nonCompressedBundle.LastExitCode) | ||
| 242 | { | ||
| 243 | WixAssert.Skip($"Uninstall exited with {nonCompressedBundle.LastExitCode}"); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | nonCompressedBundle.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 248 | packageA.VerifyInstalled(false); | ||
| 249 | |||
| 250 | return installLogPath; | ||
| 251 | } | ||
| 252 | finally | ||
| 253 | { | ||
| 254 | Environment.SetEnvironmentVariable("TMP", originalTemp); | ||
| 255 | |||
| 256 | if (deletePolicyKey) | ||
| 257 | { | ||
| 258 | Registry.LocalMachine.DeleteSubKeyTree(policyPath); | ||
| 259 | } | ||
| 260 | else | ||
| 261 | { | ||
| 262 | using (var policyKey = Registry.LocalMachine.OpenSubKey(policyPath, writable: true)) | ||
| 263 | { | ||
| 264 | policyKey?.SetValue("EngineWorkingDirectory", originalEngineWorkingDirectoryValue); | ||
| 265 | policyKey?.SetValue("PackageCache", originalPackageCacheValue); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | private static string GetLongPath(string baseFolder) | ||
| 272 | { | ||
| 273 | Directory.CreateDirectory(baseFolder); | ||
| 274 | |||
| 275 | // Try to create a directory that is longer than MAX_PATH but without the \\?\ prefix to detect OS support for long paths. | ||
| 276 | // Need to PInvoke CreateDirectoryW directly because .NET methods will append the \\?\ prefix. | ||
| 277 | foreach (var c in new char[] { 'a', 'b', 'c' }) | ||
| 278 | { | ||
| 279 | baseFolder = Path.Combine(baseFolder, new string(c, 100)); | ||
| 280 | if (!CreateDirectoryW(baseFolder, IntPtr.Zero)) | ||
| 281 | { | ||
| 282 | int lastError = Marshal.GetLastWin32Error(); | ||
| 283 | if (lastError == 206) | ||
| 284 | { | ||
| 285 | WixAssert.Skip($"MAX_PATH is being enforced ({baseFolder})"); | ||
| 286 | } | ||
| 287 | throw new Win32Exception(lastError); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | return baseFolder; | ||
| 292 | } | ||
| 293 | |||
| 294 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
| 295 | [return: MarshalAs(UnmanagedType.Bool)] | ||
| 296 | private extern static bool CreateDirectoryW(string lpPathName, IntPtr lpSecurityAttributes); | ||
| 297 | } | ||
| 298 | } | ||
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/testhost.longpathaware.manifest b/src/test/burn/WixToolsetTest.BurnE2E/testhost.longpathaware.manifest new file mode 100644 index 00000000..a56ab91a --- /dev/null +++ b/src/test/burn/WixToolsetTest.BurnE2E/testhost.longpathaware.manifest | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
| 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 | |||
| 5 | <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> | ||
| 6 | <application xmlns="urn:schemas-microsoft-com:asm.v3"> | ||
| 7 | <windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> | ||
| 8 | <ws2:longPathAware>true</ws2:longPathAware> | ||
| 9 | </windowsSettings> | ||
| 10 | </application> | ||
| 11 | </assembly> | ||
diff --git a/src/test/burn/test_burn.cmd b/src/test/burn/test_burn.cmd index 83401614..80467f39 100644 --- a/src/test/burn/test_burn.cmd +++ b/src/test/burn/test_burn.cmd | |||
| @@ -9,11 +9,16 @@ | |||
| 9 | @if /i "%1"=="test" set RuntimeTestsEnabled=true | 9 | @if /i "%1"=="test" set RuntimeTestsEnabled=true |
| 10 | @if not "%1"=="" shift & goto parse_args | 10 | @if not "%1"=="" shift & goto parse_args |
| 11 | 11 | ||
| 12 | @set _B=%~dp0..\..\..\build\IntegrationBurn\%_C% | ||
| 13 | |||
| 12 | @echo Burn integration tests %_C% | 14 | @echo Burn integration tests %_C% |
| 13 | 15 | ||
| 14 | msbuild -t:Build -Restore -p:Configuration=%_C% -warnaserror -bl:%_L%\test_burn_build.binlog || exit /b | 16 | msbuild -t:Build -Restore -p:Configuration=%_C% -warnaserror -bl:%_L%\test_burn_build.binlog || exit /b |
| 15 | msbuild -t:Build -Restore TestData\TestData.proj -p:Configuration=%_C% -m -bl:%_L%\test_burn_data_build.binlog || exit /b | 17 | msbuild -t:Build -Restore TestData\TestData.proj -p:Configuration=%_C% -m -bl:%_L%\test_burn_data_build.binlog || exit /b |
| 16 | 18 | ||
| 19 | "%_B%\net35\win-x86\testexe.exe" /dm "%_B%\netcoreapp3.1\testhost.exe" | ||
| 20 | mt.exe -manifest "WixToolsetTest.BurnE2E\testhost.longpathaware.manifest" -updateresource:"%_B%\netcoreapp3.1\testhost.exe" | ||
| 21 | |||
| 17 | @if not "%RuntimeTestsEnabled%"=="true" goto :LExit | 22 | @if not "%RuntimeTestsEnabled%"=="true" goto :LExit |
| 18 | 23 | ||
| 19 | dotnet test -c %_C% --no-build WixToolsetTest.BurnE2E -l "trx;LogFileName=%_L%\TestResults\WixToolsetTest.BurnE2E.trx" || exit /b | 24 | dotnet test -c %_C% --no-build WixToolsetTest.BurnE2E -l "trx;LogFileName=%_L%\TestResults\WixToolsetTest.BurnE2E.trx" || exit /b |
