Make all tests pass on Linux (#8)

- Select filename to execute based on RuntimeIdentifier
- Include server log in error message if Run or Exec http requests fail
- Angular: Normalize hash in main.[HASH].bundle.js
- React: Disable parallelism to avoid exceeding default fs.inotify.max_user_watches limit
This commit is contained in:
Mike Harder 2018-05-11 11:02:04 -07:00 committed by GitHub
parent 5dfdf604a9
commit 0fa02f424f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 19 deletions

View File

@ -1,5 +1,6 @@
using AspNetCoreSdkTests.Templates;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
@ -36,19 +37,51 @@ namespace AspNetCoreSdkTests
[TestCaseSource(nameof(RunData))]
public void Run(Template template)
{
Assert.AreEqual(HttpStatusCode.OK, template.HttpResponseAfterRun.StatusCode);
Assert.AreEqual(HttpStatusCode.OK, template.HttpsResponseAfterRun.StatusCode);
var statusCode = template.HttpResponseAfterRun.StatusCode;
Assert.AreEqual(HttpStatusCode.OK, statusCode,
GetMessage(statusCode, template.ServerOutputAfterRun, template.ServerErrorAfterRun));
statusCode = template.HttpsResponseAfterRun.StatusCode;
Assert.AreEqual(HttpStatusCode.OK, statusCode,
GetMessage(statusCode, template.ServerOutputAfterRun, template.ServerErrorAfterRun));
}
[NonParallelizable]
[Test]
[TestCaseSource(nameof(RunNonParallelizableData))]
public void RunNonParallelizable(Template template)
{
Run(template);
}
[Test]
[TestCaseSource(nameof(ExecData))]
public void Exec(Template template)
{
Assert.AreEqual(HttpStatusCode.OK, template.HttpResponseAfterExec.StatusCode);
Assert.AreEqual(HttpStatusCode.OK, template.HttpsResponseAfterExec.StatusCode);
var statusCode = template.HttpResponseAfterExec.StatusCode;
Assert.AreEqual(HttpStatusCode.OK, statusCode,
GetMessage(statusCode, template.ServerOutputAfterExec, template.ServerErrorAfterExec));
statusCode = template.HttpsResponseAfterExec.StatusCode;
Assert.AreEqual(HttpStatusCode.OK, statusCode,
GetMessage(statusCode, template.ServerOutputAfterExec, template.ServerErrorAfterExec));
}
private static IEnumerable<Template> _restoreTemplates = new[]
private static string GetMessage(HttpStatusCode statusCode, string serverOutput, string serverError)
{
return String.Join(Environment.NewLine,
$"StatusCode: {statusCode}",
string.Empty,
"ServerOutput",
"------------",
serverOutput,
string.Empty,
"ServerError",
"------------",
serverError);
}
private static readonly IEnumerable<Template> _restoreTemplates = new[]
{
// Framework-dependent
Template.GetInstance<ClassLibraryTemplate>(NuGetPackageSource.None, RuntimeIdentifier.None),
@ -103,13 +136,13 @@ namespace AspNetCoreSdkTests
Template.GetInstance<WebApiTemplate>(NuGetPackageSource.NuGetOrg, RuntimeIdentifier.OSX_x64),
};
public static IEnumerable<TestCaseData> RestoreData = _restoreTemplates.Select(t => new TestCaseData(t));
public static IEnumerable<TestCaseData> RestoreData = _restoreTemplates.Select(t => new TestCaseData(t)).ToList();
public static IEnumerable<TestCaseData> BuildData => RestoreData;
public static IEnumerable<TestCaseData> PublishData => BuildData;
public static IEnumerable<TestCaseData> RunData =
private static readonly IEnumerable<TestCaseData> _runData =
from tcd in BuildData
let t = (Template)tcd.Arguments[0]
// Only interested in verifying web applications
@ -118,6 +151,18 @@ namespace AspNetCoreSdkTests
where (t.RuntimeIdentifier == RuntimeIdentifier.None)
select tcd;
// On Linux, calling "dotnet run" on multiple React templates in parallel may fail since the default
// fs.inotify.max_user_watches is too low. One workaround is to increase fs.inotify.max_user_watches,
// but this means tests will fail on a default machine. A simpler workaround is to disable parallel
// execution for these tests.
public static IEnumerable<TestCaseData> RunNonParallelizableData =
from tcd in _runData
let t = (Template)tcd.Arguments[0]
where (t is ReactTemplate)
select tcd;
public static IEnumerable<TestCaseData> RunData = _runData.Except(RunNonParallelizableData);
public static IEnumerable<TestCaseData> ExecData =
from tcd in PublishData
let t = (Template)tcd.Arguments[0]

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace AspNetCoreSdkTests.Templates
{
@ -10,6 +11,12 @@ namespace AspNetCoreSdkTests.Templates
public override string Name => "angular";
// For some reason, the generated hash in main.[HASH].bundle.js is different on Windows and Linux, despite
// the file contents being identical. Replacing the generated hash with "[HASH]" allows the tests to pass
// on both platforms.
public override IEnumerable<string> FilesAfterPublish =>
base.FilesAfterPublish.Select(f => Regex.Replace(f, @"main\.[0-9a-f]*\.bundle\.js$", "main.[HASH].bundle.js"));
public override IEnumerable<string> ExpectedFilesAfterPublish =>
base.ExpectedFilesAfterPublish
.Concat(new[]
@ -23,7 +30,7 @@ namespace AspNetCoreSdkTests.Templates
Path.Combine("ClientApp", "dist", "glyphicons-halflings-regular.fa2772327f55d8198301.woff"),
Path.Combine("ClientApp", "dist", "index.html"),
Path.Combine("ClientApp", "dist", "inline.318b50c57b4eba3d437b.bundle.js"),
Path.Combine("ClientApp", "dist", "main.d2eed1593a6df639e365.bundle.js"),
Path.Combine("ClientApp", "dist", "main.[HASH].bundle.js"),
Path.Combine("ClientApp", "dist", "polyfills.bf95165a1d5098766b92.bundle.js"),
Path.Combine("ClientApp", "dist", "styles.2727681ffee5a66f9fe6.bundle.css"),
});

View File

@ -33,8 +33,8 @@ namespace AspNetCoreSdkTests.Templates
private Lazy<IEnumerable<string>> _objFilesAfterRestore;
private Lazy<(IEnumerable<string> ObjFiles, IEnumerable<string> BinFiles)> _filesAfterBuild;
private Lazy<IEnumerable<string>> _filesAfterPublish;
private Lazy<(HttpResponseMessage Http, HttpResponseMessage Https)> _httpResponsesAfterRun;
private Lazy<(HttpResponseMessage Http, HttpResponseMessage Https)> _httpResponsesAfterExec;
private Lazy<(HttpResponseMessage Http, HttpResponseMessage Https, string ServerOutput, string ServerError )> _httpResponsesAfterRun;
private Lazy<(HttpResponseMessage Http, HttpResponseMessage Https, string ServerOutput, string ServerError)> _httpResponsesAfterExec;
public NuGetPackageSource NuGetPackageSource { get; private set; }
public RuntimeIdentifier RuntimeIdentifier { get; private set; }
@ -50,10 +50,10 @@ namespace AspNetCoreSdkTests.Templates
_filesAfterPublish = new Lazy<IEnumerable<string>>(
GetFilesAfterPublish, LazyThreadSafetyMode.ExecutionAndPublication);
_httpResponsesAfterRun = new Lazy<(HttpResponseMessage Http, HttpResponseMessage Https)>(
_httpResponsesAfterRun = new Lazy<(HttpResponseMessage Http, HttpResponseMessage Https, string ServerOutput, string ServerError)>(
GetHttpResponsesAfterRun, LazyThreadSafetyMode.ExecutionAndPublication);
_httpResponsesAfterExec = new Lazy<(HttpResponseMessage Http, HttpResponseMessage Https)>(
_httpResponsesAfterExec = new Lazy<(HttpResponseMessage Http, HttpResponseMessage Https, string ServerOutput, string ServerError)>(
GetHttpResponsesAfterExec, LazyThreadSafetyMode.ExecutionAndPublication);
}
@ -69,11 +69,15 @@ namespace AspNetCoreSdkTests.Templates
public IEnumerable<string> ObjFilesAfterRestore => _objFilesAfterRestore.Value;
public IEnumerable<string> ObjFilesAfterBuild => _filesAfterBuild.Value.ObjFiles;
public IEnumerable<string> BinFilesAfterBuild => _filesAfterBuild.Value.BinFiles;
public IEnumerable<string> FilesAfterPublish => _filesAfterPublish.Value;
public virtual IEnumerable<string> FilesAfterPublish => _filesAfterPublish.Value;
public HttpResponseMessage HttpResponseAfterRun => _httpResponsesAfterRun.Value.Http;
public HttpResponseMessage HttpsResponseAfterRun => _httpResponsesAfterRun.Value.Https;
public string ServerOutputAfterRun => _httpResponsesAfterRun.Value.ServerOutput;
public string ServerErrorAfterRun => _httpResponsesAfterRun.Value.ServerError;
public HttpResponseMessage HttpResponseAfterExec => _httpResponsesAfterExec.Value.Http;
public HttpResponseMessage HttpsResponseAfterExec => _httpResponsesAfterExec.Value.Https;
public string ServerOutputAfterExec => _httpResponsesAfterExec.Value.ServerOutput;
public string ServerErrorAfterExec => _httpResponsesAfterExec.Value.ServerError;
public virtual IEnumerable<string> ExpectedObjFilesAfterRestore => new[]
{
@ -115,7 +119,7 @@ namespace AspNetCoreSdkTests.Templates
return IOUtil.GetFiles(Path.Combine(TempDir, DotNetUtil.PublishOutput));
}
private (HttpResponseMessage Http, HttpResponseMessage Https) GetHttpResponsesAfterRun()
private (HttpResponseMessage Http, HttpResponseMessage Https, string ServerOutput, string ServerError) GetHttpResponsesAfterRun()
{
// Run depends on Build
_ = BinFilesAfterBuild;
@ -123,7 +127,7 @@ namespace AspNetCoreSdkTests.Templates
return GetHttpResponses(DotNetUtil.Run(TempDir, RuntimeIdentifier));
}
private (HttpResponseMessage Http, HttpResponseMessage Https) GetHttpResponsesAfterExec()
private (HttpResponseMessage Http, HttpResponseMessage Https, string ServerOutput, string ServerError) GetHttpResponsesAfterExec()
{
// Exec depends on Publish
_ = FilesAfterPublish;
@ -131,13 +135,18 @@ namespace AspNetCoreSdkTests.Templates
return GetHttpResponses(DotNetUtil.Exec(TempDir, Name, RuntimeIdentifier));
}
private (HttpResponseMessage Http, HttpResponseMessage Https) GetHttpResponses(
private (HttpResponseMessage Http, HttpResponseMessage Https, string ServerOutput, string ServerError) GetHttpResponses(
(Process Process, ConcurrentStringBuilder OutputBuilder, ConcurrentStringBuilder ErrorBuilder) process)
{
try
{
var (httpUrl, httpsUrl) = ScrapeUrls(process);
return (GetAsync(new Uri(new Uri(httpUrl), RelativeUrl)), GetAsync(new Uri(new Uri(httpsUrl), RelativeUrl)));
return (
Get(new Uri(new Uri(httpUrl), RelativeUrl)),
Get(new Uri(new Uri(httpsUrl), RelativeUrl)),
process.OutputBuilder.ToString(),
process.ErrorBuilder.ToString()
);
}
finally
{
@ -171,7 +180,7 @@ namespace AspNetCoreSdkTests.Templates
}
}
private HttpResponseMessage GetAsync(Uri requestUri)
private HttpResponseMessage Get(Uri requestUri)
{
while (true)
{

View File

@ -71,7 +71,8 @@ namespace AspNetCoreSdkTests.Util
}
else
{
var path = Path.Combine(workingDirectory, PublishOutput, $"{name}.exe");
var file = (runtimeIdentifier == RuntimeIdentifier.Win_x64) ? $"{name}.exe" : name;
var path = Path.Combine(workingDirectory, PublishOutput, file);
return StartProcess(path, _urls, workingDirectory);
}
}