summaryrefslogtreecommitdiff
path: root/src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs')
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/LongPathTests.cs298
1 files changed, 298 insertions, 0 deletions
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
3namespace 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}