diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2021-02-17 15:46:23 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2021-02-17 16:20:10 -0600 |
commit | 15b1946325bf1cfd1794b997f2cbbbcfeb648e92 (patch) | |
tree | 511a4c77ac2de6feeb153bdc541950a14f8031e3 | |
parent | badde27bf66fcacef2d625af0bd7590ecdc5804f (diff) | |
download | wix-15b1946325bf1cfd1794b997f2cbbbcfeb648e92.tar.gz wix-15b1946325bf1cfd1794b997f2cbbbcfeb648e92.tar.bz2 wix-15b1946325bf1cfd1794b997f2cbbbcfeb648e92.zip |
Port the rest of the FailureTests from the old repo.
-rw-r--r-- | src/TestData/FailureTests/BundleB/Bundle.wxs | 26 | ||||
-rw-r--r-- | src/TestData/FailureTests/BundleB/BundleB.wixproj | 16 | ||||
-rw-r--r-- | src/TestData/FailureTests/BundleC/BundleC.wixproj | 19 | ||||
-rw-r--r-- | src/TestData/FailureTests/BundleC/BundleC.wxs | 11 | ||||
-rw-r--r-- | src/WixTestTools/LogVerifier.cs | 252 | ||||
-rw-r--r-- | src/WixToolsetTest.BurnE2E/FailureTests.cs | 45 |
6 files changed, 369 insertions, 0 deletions
diff --git a/src/TestData/FailureTests/BundleB/Bundle.wxs b/src/TestData/FailureTests/BundleB/Bundle.wxs new file mode 100644 index 00000000..ea3d029e --- /dev/null +++ b/src/TestData/FailureTests/BundleB/Bundle.wxs | |||
@@ -0,0 +1,26 @@ | |||
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 | <?ifndef Version?> | ||
4 | <?define Version = 1.0.0.0?> | ||
5 | <?endif?> | ||
6 | |||
7 | <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"> | ||
9 | <Log Prefix="~$(var.TestGroupName)_$(var.BundleName)" /> | ||
10 | |||
11 | <Variable Name="TestGroupName" Value="$(var.TestGroupName)" /> | ||
12 | |||
13 | <!-- ParallelCache="yes" should be the only thing different from the template --> | ||
14 | <Chain ParallelCache="yes"> | ||
15 | <PackageGroupRef Id="TestBA" /> | ||
16 | |||
17 | <PackageGroupRef Id="BundlePackages" /> | ||
18 | </Chain> | ||
19 | </Bundle> | ||
20 | <Fragment> | ||
21 | <PackageGroup Id="BundlePackages"> | ||
22 | <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" /> | ||
23 | <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" /> | ||
24 | </PackageGroup> | ||
25 | </Fragment> | ||
26 | </Wix> | ||
diff --git a/src/TestData/FailureTests/BundleB/BundleB.wixproj b/src/TestData/FailureTests/BundleB/BundleB.wixproj new file mode 100644 index 00000000..6d36d120 --- /dev/null +++ b/src/TestData/FailureTests/BundleB/BundleB.wixproj | |||
@@ -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 | <PropertyGroup> | ||
4 | <OutputType>Bundle</OutputType> | ||
5 | <UpgradeCode>{C60B9483-CE87-4FDA-AE5A-B39A52E956E8}</UpgradeCode> | ||
6 | </PropertyGroup> | ||
7 | <ItemGroup> | ||
8 | <ProjectReference Include="..\PackageA\PackageA.wixproj" /> | ||
9 | <ProjectReference Include="..\PackageB\PackageB.wixproj" /> | ||
10 | <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" /> | ||
11 | </ItemGroup> | ||
12 | <ItemGroup> | ||
13 | <PackageReference Include="WixToolset.Bal.wixext" Version="4.0.83" /> | ||
14 | <PackageReference Include="WixToolset.NetFx.wixext" Version="4.0.61" /> | ||
15 | </ItemGroup> | ||
16 | </Project> \ No newline at end of file | ||
diff --git a/src/TestData/FailureTests/BundleC/BundleC.wixproj b/src/TestData/FailureTests/BundleC/BundleC.wixproj new file mode 100644 index 00000000..03f611fc --- /dev/null +++ b/src/TestData/FailureTests/BundleC/BundleC.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>{9E9964D0-2120-4358-8136-D4A8727E0C59}</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.83" /> | ||
17 | <PackageReference Include="WixToolset.NetFx.wixext" Version="4.0.61" /> | ||
18 | </ItemGroup> | ||
19 | </Project> \ No newline at end of file | ||
diff --git a/src/TestData/FailureTests/BundleC/BundleC.wxs b/src/TestData/FailureTests/BundleC/BundleC.wxs new file mode 100644 index 00000000..48c4ab72 --- /dev/null +++ b/src/TestData/FailureTests/BundleC/BundleC.wxs | |||
@@ -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)" Name="MissingNonVital.msi" Vital="no" Compressed="no" /> | ||
8 | <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" /> | ||
9 | </PackageGroup> | ||
10 | </Fragment> | ||
11 | </Wix> | ||
diff --git a/src/WixTestTools/LogVerifier.cs b/src/WixTestTools/LogVerifier.cs new file mode 100644 index 00000000..0252a9f9 --- /dev/null +++ b/src/WixTestTools/LogVerifier.cs | |||
@@ -0,0 +1,252 @@ | |||
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 WixTestTools | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using System.Text; | ||
8 | using System.Text.RegularExpressions; | ||
9 | using Xunit; | ||
10 | |||
11 | /// <summary> | ||
12 | /// The LogVerifier can verify a log file for given regular expressions. | ||
13 | /// </summary> | ||
14 | public class LogVerifier | ||
15 | { | ||
16 | // Member Variables | ||
17 | private string logFile; | ||
18 | |||
19 | /// <summary> | ||
20 | /// Prevent creation of LogVerifier without log file | ||
21 | /// </summary> | ||
22 | private LogVerifier() | ||
23 | { } | ||
24 | |||
25 | /// <summary> | ||
26 | /// Constructor for log files where the exact file name is known. | ||
27 | /// </summary> | ||
28 | /// <param name="fileName">The full path to the log file</param> | ||
29 | public LogVerifier(string fileName) | ||
30 | { | ||
31 | if (null == fileName) | ||
32 | throw new ArgumentNullException("fileName"); | ||
33 | |||
34 | if (!File.Exists(fileName)) | ||
35 | throw new ArgumentException(String.Format(@"File doesn't exist:{0}", fileName), "fileName"); | ||
36 | |||
37 | logFile = fileName; | ||
38 | } | ||
39 | |||
40 | /// <summary> | ||
41 | /// Constructor for log files where the exact file name is known. | ||
42 | /// </summary> | ||
43 | /// <param name="directory">The directory in which the log file is located.</param> | ||
44 | /// <param name="fileName">The name of the log file.</param> | ||
45 | public LogVerifier(string directory, string fileName) | ||
46 | : this(Path.Combine(directory, fileName)) | ||
47 | { } | ||
48 | |||
49 | /// <summary> | ||
50 | /// Scans a log file line by line until the regex pattern is matched or eof is reached. | ||
51 | /// This method would be used in the case where the log file is very large, the regex doesn't | ||
52 | /// span multiple lines, and only one match is required. | ||
53 | /// </summary> | ||
54 | /// <param name="regex">A regular expression</param> | ||
55 | /// <returns>True if a match is found, False otherwise.</returns> | ||
56 | public bool LineByLine(Regex regex) | ||
57 | { | ||
58 | string line = string.Empty; | ||
59 | StreamReader sr = new StreamReader(logFile); | ||
60 | |||
61 | // Read from a file stream line by line. | ||
62 | while ((line = sr.ReadLine()) != null) | ||
63 | { | ||
64 | if (regex.Match(line).Success) | ||
65 | { | ||
66 | sr.Close(); | ||
67 | sr.Dispose(); | ||
68 | return true; | ||
69 | } | ||
70 | } | ||
71 | return false; | ||
72 | } | ||
73 | |||
74 | |||
75 | /// <summary> | ||
76 | /// Scans a log file line by line until the regex pattern is matched or eof is reached. | ||
77 | /// This method would be used in the case where the log file is very large, the regex doesn't | ||
78 | /// span multiple lines, and only one match is required. | ||
79 | /// No RegexOptions are used and matches are case sensitive. | ||
80 | /// </summary> | ||
81 | /// <param name="regex">A regular expression string.</param> | ||
82 | /// <returns>True if a match is found, False otherwise.</returns> | ||
83 | public bool LineByLine(string regex) | ||
84 | { | ||
85 | return LineByLine(new Regex(regex)); | ||
86 | } | ||
87 | |||
88 | |||
89 | /// <summary> | ||
90 | /// Scans a log file for matches to the regex. | ||
91 | /// </summary> | ||
92 | /// <param name="regex">A regular expression</param> | ||
93 | /// <returns>The number of matches</returns> | ||
94 | public int EntireFileAtOnce(Regex regex) | ||
95 | { | ||
96 | string logFileText = this.ReadLogFile(); | ||
97 | return regex.Matches(logFileText).Count; | ||
98 | } | ||
99 | |||
100 | /// <summary> | ||
101 | /// Scans a log file for matches to the regex. | ||
102 | /// </summary> | ||
103 | /// <param name="regex">A regular expression</param> | ||
104 | /// <returns>The number of matches</returns> | ||
105 | public bool EntireFileAtOncestr(string regex) | ||
106 | { | ||
107 | string logFileText = this.ReadLogFile(); | ||
108 | return logFileText.Contains(regex); | ||
109 | } | ||
110 | /// <summary> | ||
111 | /// Scans a log file for matches to the regex string. | ||
112 | /// Only the Multiline RegexOption is used and matches are case sensitive. | ||
113 | /// </summary> | ||
114 | /// <param name="regex">A regular expression</param> | ||
115 | /// <returns>The number of matches</returns> | ||
116 | public int EntireFileAtOnce(string regex) | ||
117 | { | ||
118 | return EntireFileAtOnce(new Regex(regex, RegexOptions.Multiline)); | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Scans a log file for matches to the regex string. | ||
123 | /// </summary> | ||
124 | /// <param name="regex">A regular expression</param> | ||
125 | /// <param name="ignoreCase">Specify whether to perform case sensitive matches</param> | ||
126 | /// <returns>The number of matches</returns> | ||
127 | public int EntireFileAtOnce(string regex, bool ignoreCase) | ||
128 | { | ||
129 | if (!ignoreCase) | ||
130 | return EntireFileAtOnce(new Regex(regex, RegexOptions.Multiline)); | ||
131 | else | ||
132 | return EntireFileAtOnce(new Regex(regex, RegexOptions.Multiline | RegexOptions.IgnoreCase)); | ||
133 | } | ||
134 | |||
135 | /// <summary> | ||
136 | /// Search through the log and Assert.Fail() if a specified string is not found. | ||
137 | /// </summary> | ||
138 | /// <param name="regex">Search expression</param> | ||
139 | /// <param name="ignoreCase">Perform case insensitive match</param> | ||
140 | public void AssertTextInLog(string regex, bool ignoreCase) | ||
141 | { | ||
142 | Assert.True(EntireFileAtOncestr(regex), | ||
143 | String.Format("The log does not contain a match to the regular expression \"{0}\" ", regex)); | ||
144 | } | ||
145 | |||
146 | /// <summary> | ||
147 | /// Search through the log and Assert.Fail() if a specified string is not found. | ||
148 | /// </summary> | ||
149 | /// <param name="regex">Search expression</param> | ||
150 | /// <param name="ignoreCase">Perform case insensitive match</param> | ||
151 | public void AssertTextInLog(Regex regex, bool ignoreCase) | ||
152 | { | ||
153 | Assert.True(EntireFileAtOnce(regex) >= 1, | ||
154 | String.Format("The log does not contain a match to the regular expression \"{0}\" ", regex.ToString())); | ||
155 | } | ||
156 | |||
157 | /// <summary> | ||
158 | /// Search through the log and Assert.Fail() if a specified string is not found. | ||
159 | /// </summary> | ||
160 | /// <param name="regex">Search expression</param> | ||
161 | /// <param name="ignoreCase">Perform case insensitive match</param> | ||
162 | public void AssertTextInLog(string regex) | ||
163 | { | ||
164 | AssertTextInLog(regex, true); | ||
165 | } | ||
166 | |||
167 | /// <summary> | ||
168 | /// Search through the log and Assert.Fail() if a specified string is not found. | ||
169 | /// </summary> | ||
170 | /// <param name="regex">Search expression</param> | ||
171 | /// <param name="ignoreCase">Perform case insensitive match</param> | ||
172 | public void AssertTextInLog(Regex regex) | ||
173 | { | ||
174 | AssertTextInLog(regex, true); | ||
175 | } | ||
176 | |||
177 | |||
178 | /// <summary> | ||
179 | /// Search through the log and Assert.Fail() if a specified string is found. | ||
180 | /// </summary> | ||
181 | /// <param name="regex">Search expression</param> | ||
182 | /// <param name="ignoreCase">Perform case insensitive match</param> | ||
183 | public void AssertTextNotInLog(Regex regex, bool ignoreCase) | ||
184 | { | ||
185 | Assert.True(EntireFileAtOnce(regex) < 1, | ||
186 | String.Format("The log contain a match to the regular expression \"{0}\" ", regex.ToString())); | ||
187 | } | ||
188 | |||
189 | /// <summary> | ||
190 | /// Search through the log and Assert.Fail() if a specified string is not found. | ||
191 | /// </summary> | ||
192 | /// <param name="regex">Search expression</param> | ||
193 | /// <param name="ignoreCase">Perform case insensitive match</param> | ||
194 | public void AssertTextNotInLog(string regex, bool ignoreCase) | ||
195 | { | ||
196 | Assert.False(EntireFileAtOncestr(regex), | ||
197 | String.Format("The log does not contain a match to the regular expression \"{0}\" ", regex)); | ||
198 | } | ||
199 | |||
200 | /// <summary> | ||
201 | /// Checks if a meesage is in a file | ||
202 | /// </summary> | ||
203 | /// <param name="logFileName">The full path to the log file</param> | ||
204 | /// <param name="message">Search expression</param> | ||
205 | /// <returns>True if the message was found, false otherwise</returns> | ||
206 | public static bool MessageInLogFile(string logFileName, string message) | ||
207 | { | ||
208 | LogVerifier logVerifier = new LogVerifier(logFileName); | ||
209 | return logVerifier.EntireFileAtOncestr(message); | ||
210 | } | ||
211 | |||
212 | /// <summary> | ||
213 | /// Checks if a meesage is in a file | ||
214 | /// </summary> | ||
215 | /// <param name="logFileName">The full path to the log file</param> | ||
216 | /// <param name="message">Search expression (regex)</param> | ||
217 | /// <returns>True if the message was found, false otherwise</returns> | ||
218 | public static bool MessageInLogFileRegex(string logFileName, string regexMessage) | ||
219 | { | ||
220 | LogVerifier logVerifier = new LogVerifier(logFileName); | ||
221 | return logVerifier.EntireFileAtOnce(regexMessage) > 0; | ||
222 | } | ||
223 | |||
224 | /// <summary> | ||
225 | /// Read in the entire log file at once. | ||
226 | /// </summary> | ||
227 | /// <returns>Contents of log file.</returns> | ||
228 | private string ReadLogFile() | ||
229 | { | ||
230 | // Retry a few times. | ||
231 | for (int retry = 0; ; ++retry) | ||
232 | { | ||
233 | try | ||
234 | { | ||
235 | using (StreamReader sr = new StreamReader(this.logFile)) | ||
236 | { | ||
237 | return sr.ReadToEnd(); | ||
238 | } | ||
239 | } | ||
240 | catch // we'll catch everything a few times until we give up. | ||
241 | { | ||
242 | if (retry > 4) | ||
243 | { | ||
244 | throw; | ||
245 | } | ||
246 | |||
247 | System.Threading.Thread.Sleep(1000); | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | } | ||
diff --git a/src/WixToolsetTest.BurnE2E/FailureTests.cs b/src/WixToolsetTest.BurnE2E/FailureTests.cs index bc505527..a11a5eb6 100644 --- a/src/WixToolsetTest.BurnE2E/FailureTests.cs +++ b/src/WixToolsetTest.BurnE2E/FailureTests.cs | |||
@@ -63,5 +63,50 @@ namespace WixToolsetTest.BurnE2E | |||
63 | packageA.VerifyInstalled(false); | 63 | packageA.VerifyInstalled(false); |
64 | packageB.VerifyInstalled(false); | 64 | packageB.VerifyInstalled(false); |
65 | } | 65 | } |
66 | |||
67 | [Fact(Skip = "https://github.com/wixtoolset/issues/issues/5750")] | ||
68 | public void CanCancelExecuteWhileCaching() | ||
69 | { | ||
70 | var packageA = this.CreatePackageInstaller("PackageA"); | ||
71 | var packageB = this.CreatePackageInstaller("PackageB"); | ||
72 | var bundleB = this.CreateBundleInstaller("BundleB"); | ||
73 | var testBAController = this.CreateTestBAController(); | ||
74 | |||
75 | // Slow the caching of package B to ensure that package A starts installing and cancels. | ||
76 | testBAController.SetPackageCancelExecuteAtProgress("PackageA", 50); | ||
77 | testBAController.SetPackageSlowCache("PackageB", 2000); | ||
78 | |||
79 | bundleB.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); | ||
80 | bundleB.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
81 | |||
82 | packageA.VerifyInstalled(false); | ||
83 | packageB.VerifyInstalled(false); | ||
84 | } | ||
85 | |||
86 | /// <summary> | ||
87 | /// BundleC has non-vital PackageA and vital PackageB. | ||
88 | /// PackageA is not compressed in the bundle and has a Name different from the source file. The Name points to a file that does not exist. | ||
89 | /// BundleC should be able to install successfully by ignoring the missing PackageA and installing PackageB. | ||
90 | /// </summary> | ||
91 | [Fact] | ||
92 | public void CanInstallWhenMissingNonVitalPackage() | ||
93 | { | ||
94 | var packageA = this.CreatePackageInstaller("PackageA"); | ||
95 | var packageB = this.CreatePackageInstaller("PackageB"); | ||
96 | var bundleC = this.CreateBundleInstaller("BundleC"); | ||
97 | |||
98 | var bundleCInstallLogFilePath = bundleC.Install(); | ||
99 | bundleC.VerifyRegisteredAndInPackageCache(); | ||
100 | Assert.True(LogVerifier.MessageInLogFileRegex(bundleCInstallLogFilePath, "Skipping apply of package: PackageA due to cache error: 0x80070002. Continuing...")); | ||
101 | |||
102 | packageA.VerifyInstalled(false); | ||
103 | packageB.VerifyInstalled(true); | ||
104 | |||
105 | bundleC.Uninstall(); | ||
106 | bundleC.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
107 | |||
108 | packageA.VerifyInstalled(false); | ||
109 | packageB.VerifyInstalled(false); | ||
110 | } | ||
66 | } | 111 | } |
67 | } | 112 | } |