[xharness] Backport a few changes to get HE0038 reporting. (#6272)
* [xharness] Show links to previous test runs in html report in server mode. (#6031) * [xharness] Change url for server mode. * [xharness] Show links to previous test runs in html report in server mode. This makes it much easier to see what failed in a previous test run. * [XHarness] Show when we have a watch HE0038 error. (#6060) To simplify the life of the monitorer, if we get a crash with a HE0038 we will propagate the result to the html and will provide a link to the issue so that it is easy to report it. * [xharness] Look for HE0038 anywhere in a log file. (#6175) Most log files now have timestamps, which means that looking for 'HE00380' at the start of each line won't work anymore. Fixes an issue where the HE0038 issue isn't detected properly.
This commit is contained in:
Родитель
6a852fdcc2
Коммит
d3c60e516b
|
@ -1481,17 +1481,21 @@ namespace xharness
|
||||||
server.Stop ();
|
server.Stop ();
|
||||||
break;
|
break;
|
||||||
case "/favicon.ico":
|
case "/favicon.ico":
|
||||||
var favicon = File.ReadAllBytes (Path.Combine (Harness.RootDirectory, "xharness", "favicon.ico"));
|
serveFile = Path.Combine (Harness.RootDirectory, "xharness", "favicon.ico");
|
||||||
response.OutputStream.Write (favicon, 0, favicon.Length);
|
|
||||||
response.OutputStream.Close ();
|
|
||||||
break;
|
|
||||||
case "/xharness.css":
|
|
||||||
case "/xharness.js":
|
|
||||||
serveFile = Path.Combine (Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly ().Location), request.Url.LocalPath.Substring (1));
|
|
||||||
goto default;
|
goto default;
|
||||||
|
case "/index.html":
|
||||||
|
var redirect_to = request.Url.AbsoluteUri.Replace ("/index.html", "/" + Path.GetFileName (LogDirectory) + "/index.html");
|
||||||
|
response.Redirect (redirect_to);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
var filename = Path.GetFileName (request.Url.LocalPath);
|
||||||
|
if (filename == "index.html" && Path.GetFileName (LogDirectory) == Path.GetFileName (Path.GetDirectoryName (request.Url.LocalPath))) {
|
||||||
|
// We're asked for the report for the current test run, so re-generate it.
|
||||||
|
GenerateReport ();
|
||||||
|
}
|
||||||
|
|
||||||
if (serveFile == null)
|
if (serveFile == null)
|
||||||
serveFile = Path.Combine (LogDirectory, request.Url.LocalPath.Substring (1));
|
serveFile = Path.Combine (Path.GetDirectoryName (LogDirectory), request.Url.LocalPath.Substring (1));
|
||||||
var path = serveFile;
|
var path = serveFile;
|
||||||
if (File.Exists (path)) {
|
if (File.Exists (path)) {
|
||||||
var buffer = new byte [4096];
|
var buffer = new byte [4096];
|
||||||
|
@ -1508,6 +1512,9 @@ namespace xharness
|
||||||
case ".js":
|
case ".js":
|
||||||
response.ContentType = "text/javascript";
|
response.ContentType = "text/javascript";
|
||||||
break;
|
break;
|
||||||
|
case ".ico":
|
||||||
|
response.ContentType = "image/png";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
|
response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
|
||||||
break;
|
break;
|
||||||
|
@ -1516,6 +1523,7 @@ namespace xharness
|
||||||
response.OutputStream.Write (buffer, 0, read);
|
response.OutputStream.Write (buffer, 0, read);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Console.WriteLine ($"404: {request.Url.LocalPath}");
|
||||||
response.StatusCode = 404;
|
response.StatusCode = 404;
|
||||||
response.OutputStream.WriteByte ((byte) '?');
|
response.OutputStream.WriteByte ((byte) '?');
|
||||||
}
|
}
|
||||||
|
@ -1535,7 +1543,7 @@ namespace xharness
|
||||||
};
|
};
|
||||||
thread.Start ();
|
thread.Start ();
|
||||||
|
|
||||||
var url = $"http://localhost:{port}/";
|
var url = $"http://localhost:{port}/" + Path.GetFileName (LogDirectory) + "/index.html";
|
||||||
Console.WriteLine ($"Launching {url} in the system's default browser.");
|
Console.WriteLine ($"Launching {url} in the system's default browser.");
|
||||||
Process.Start ("open", url);
|
Process.Start ("open", url);
|
||||||
|
|
||||||
|
@ -1636,12 +1644,31 @@ namespace xharness
|
||||||
foreach (var file in new string [] { "xharness.js", "xharness.css" }) {
|
foreach (var file in new string [] { "xharness.js", "xharness.css" }) {
|
||||||
File.Copy (Path.Combine (dependentFileLocation, file), Path.Combine (LogDirectory, file), true);
|
File.Copy (Path.Combine (dependentFileLocation, file), Path.Combine (LogDirectory, file), true);
|
||||||
}
|
}
|
||||||
|
File.Copy (Path.Combine (Harness.RootDirectory, "xharness", "favicon.ico"), Path.Combine (LogDirectory, "favicon.ico"), true);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.MainLog.WriteLine ("Failed to write log: {0}", e);
|
this.MainLog.WriteLine ("Failed to write log: {0}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsHE0038Error (Log log) {
|
||||||
|
if (log == null)
|
||||||
|
return false;
|
||||||
|
if (File.Exists (log.FullPath) && new FileInfo (log.FullPath).Length > 0) {
|
||||||
|
using (var reader = log.GetReader ()) {
|
||||||
|
while (!reader.EndOfStream) {
|
||||||
|
string line = reader.ReadLine ();
|
||||||
|
if (line == null)
|
||||||
|
continue;
|
||||||
|
if (line.Contains ("error HE0038: Failed to launch the app"))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string previous_test_runs;
|
||||||
void GenerateReportImpl (Stream stream, StreamWriter markdown_summary = null)
|
void GenerateReportImpl (Stream stream, StreamWriter markdown_summary = null)
|
||||||
{
|
{
|
||||||
var id_counter = 0;
|
var id_counter = 0;
|
||||||
|
@ -1819,7 +1846,7 @@ namespace xharness
|
||||||
} else {
|
} else {
|
||||||
writer.Write ($"No tests selected.");
|
writer.Write ($"No tests selected.");
|
||||||
}
|
}
|
||||||
writer.WriteLine ("</span>");
|
writer.Write ("</span>");
|
||||||
writer.WriteLine ("</h2>");
|
writer.WriteLine ("</h2>");
|
||||||
if (allTasks.Count > 0) {
|
if (allTasks.Count > 0) {
|
||||||
writer.WriteLine ($"<ul id='nav'>");
|
writer.WriteLine ($"<ul id='nav'>");
|
||||||
|
@ -1827,34 +1854,34 @@ namespace xharness
|
||||||
writer.WriteLine (@"
|
writer.WriteLine (@"
|
||||||
<li>Select
|
<li>Select
|
||||||
<ul>
|
<ul>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""select?all"");'>All tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/select?all"");'>All tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""select?all-device"");'>All device tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/select?all-device"");'>All device tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""select?all-simulator"");'>All simulator tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/select?all-simulator"");'>All simulator tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""select?all-ios"");'>All iOS tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/select?all-ios"");'>All iOS tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""select?all-tvos"");'>All tvOS tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/select?all-tvos"");'>All tvOS tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""select?all-watchos"");'>All watchOS tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/select?all-watchos"");'>All watchOS tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""select?all-mac"");'>All Mac tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/select?all-mac"");'>All Mac tests</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>Deselect
|
<li>Deselect
|
||||||
<ul>
|
<ul>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""deselect?all"");'>All tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/deselect?all"");'>All tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""deselect?all-device"");'>All device tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/deselect?all-device"");'>All device tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""deselect?all-simulator"");'>All simulator tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/deselect?all-simulator"");'>All simulator tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""deselect?all-ios"");'>All iOS tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/deselect?all-ios"");'>All iOS tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""deselect?all-tvos"");'>All tvOS tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/deselect?all-tvos"");'>All tvOS tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""deselect?all-watchos"");'>All watchOS tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/deselect?all-watchos"");'>All watchOS tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""deselect?all-mac"");'>All Mac tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/deselect?all-mac"");'>All Mac tests</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>Execute
|
<li>Execute
|
||||||
<ul>
|
<ul>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""run?alltests"");'>Run all tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/run?alltests"");'>Run all tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""run?selected"");'>Run all selected tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/run?selected"");'>Run all selected tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""run?failed"");'>Run all failed tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/run?failed"");'>Run all failed tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""build?all"");'>Build all tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/build?all"");'>Build all tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""build?selected"");'>Build all selected tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/build?selected"");'>Build all selected tests</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""build?failed"");'>Build all failed tests</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/build?failed"");'>Build all failed tests</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>");
|
</li>");
|
||||||
}
|
}
|
||||||
|
@ -1870,19 +1897,51 @@ namespace xharness
|
||||||
writer.WriteLine ($@"
|
writer.WriteLine ($@"
|
||||||
<li>Reload
|
<li>Reload
|
||||||
<ul>
|
<ul>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""reload-devices"");'>Devices</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/reload-devices"");'>Devices</a></li>
|
||||||
<li class=""adminitem""><a href='javascript:sendrequest (""reload-simulators"");'>Simulators</a></li>
|
<li class=""adminitem""><a href='javascript:sendrequest (""/reload-simulators"");'>Simulators</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>Options
|
<li>Options
|
||||||
<ul>
|
<ul>
|
||||||
<li class=""adminitem""><span id='{id_counter++}' class='autorefreshable'><a href='javascript:sendrequest (""set-option?{(CleanSuccessfulTestRuns ? "do-not-clean" : "clean")}"");'>&#x{(CleanSuccessfulTestRuns ? "2705" : "274C")} Clean successful test runs</a></span></li>
|
<li class=""adminitem""><span id='{id_counter++}' class='autorefreshable'><a href='javascript:sendrequest (""/set-option?{(CleanSuccessfulTestRuns ? "do-not-clean" : "clean")}"");'>&#x{(CleanSuccessfulTestRuns ? "2705" : "274C")} Clean successful test runs</a></span></li>
|
||||||
<li class=""adminitem""><span id='{id_counter++}' class='autorefreshable'><a href='javascript:sendrequest (""set-option?{(UninstallTestApp ? "do-not-uninstall-test-app" : "uninstall-test-app")}"");'>&#x{(UninstallTestApp ? "2705" : "274C")} Uninstall the app from device before and after the test run</a></span></li>
|
<li class=""adminitem""><span id='{id_counter++}' class='autorefreshable'><a href='javascript:sendrequest (""/set-option?{(UninstallTestApp ? "do-not-uninstall-test-app" : "uninstall-test-app")}"");'>&#x{(UninstallTestApp ? "2705" : "274C")} Uninstall the app from device before and after the test run</a></span></li>
|
||||||
<li class=""adminitem""><span id='{id_counter++}' class='autorefreshable'><a href='javascript:sendrequest (""set-option?{(Harness.IncludeSystemPermissionTests ? "skip-permission-tests" : "include-permission-tests")}"");'>&#x{(Harness.IncludeSystemPermissionTests ? "2705" : "274C")} Run tests that require system permissions (might put up permission dialogs)</a></span></li>
|
<li class=""adminitem""><span id='{id_counter++}' class='autorefreshable'><a href='javascript:sendrequest (""/set-option?{(Harness.IncludeSystemPermissionTests ? "skip-permission-tests" : "include-permission-tests")}"");'>&#x{(Harness.IncludeSystemPermissionTests ? "2705" : "274C")} Run tests that require system permissions (might put up permission dialogs)</a></span></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
");
|
");
|
||||||
|
if (previous_test_runs == null) {
|
||||||
|
var sb = new StringBuilder ();
|
||||||
|
var previous = Directory.GetDirectories (Path.GetDirectoryName (LogDirectory)).
|
||||||
|
Select ((v) => Path.Combine (v, "index.html")).
|
||||||
|
Where (File.Exists);
|
||||||
|
if (previous.Any ()) {
|
||||||
|
sb.AppendLine ("\t<li>Previous test runs");
|
||||||
|
sb.AppendLine ("\t\t<ul>");
|
||||||
|
foreach (var prev in previous) {
|
||||||
|
var dir = Path.GetFileName (Path.GetDirectoryName (prev));
|
||||||
|
var ts = dir;
|
||||||
|
var description = File.ReadAllLines (prev).Where ((v) => v.StartsWith ("<h2", StringComparison.Ordinal)).FirstOrDefault ();
|
||||||
|
if (description != null) {
|
||||||
|
description = description.Substring (description.IndexOf ('>') + 1); // <h2 ...>
|
||||||
|
description = description.Substring (description.IndexOf ('>') + 1); // <span id= ...>
|
||||||
|
|
||||||
|
var h2end = description.LastIndexOf ("</h2>", StringComparison.Ordinal);
|
||||||
|
if (h2end > -1)
|
||||||
|
description = description.Substring (0, h2end);
|
||||||
|
description = description.Substring (0, description.LastIndexOf ('<'));
|
||||||
|
} else {
|
||||||
|
description = "<unknown state>";
|
||||||
|
}
|
||||||
|
sb.AppendLine ($"\t\t\t<li class=\"adminitem\"><a href='/{dir}/index.html'>{ts}: {description}</a></li>");
|
||||||
|
}
|
||||||
|
sb.AppendLine ("\t\t</ul>");
|
||||||
|
sb.AppendLine ("\t</li>");
|
||||||
|
}
|
||||||
|
previous_test_runs = sb.ToString ();
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty (previous_test_runs))
|
||||||
|
writer.Write (previous_test_runs);
|
||||||
}
|
}
|
||||||
writer.WriteLine ("</ul>");
|
writer.WriteLine ("</ul>");
|
||||||
}
|
}
|
||||||
|
@ -1974,7 +2033,12 @@ namespace xharness
|
||||||
|
|
||||||
writer.Write ($"<div class='pdiv {ignoredClass}'>");
|
writer.Write ($"<div class='pdiv {ignoredClass}'>");
|
||||||
writer.Write ($"<span id='button_{log_id}' class='expander' onclick='javascript: toggleLogVisibility (\"{log_id}\");'>{defaultExpander}</span>");
|
writer.Write ($"<span id='button_{log_id}' class='expander' onclick='javascript: toggleLogVisibility (\"{log_id}\");'>{defaultExpander}</span>");
|
||||||
|
// we have a very common error we want to make this easier for the person that is dealing with the results
|
||||||
|
if (test.ExecutionResult == TestExecutingResult.Crashed && IsHE0038Error (logs.First (l => l.Description == "Run log"))) {
|
||||||
|
writer.Write ($"<span id='x{id_counter++}' class='p3 autorefreshable' onclick='javascript: toggleLogVisibility (\"{log_id}\");'>{title} (<span style='color: {GetTestColor (test)}'>{state} <a href='https://github.com/xamarin/maccore/issues/581'>HE0038</a></span>{buildOnly}) </span>");
|
||||||
|
} else {
|
||||||
writer.Write ($"<span id='x{id_counter++}' class='p3 autorefreshable' onclick='javascript: toggleLogVisibility (\"{log_id}\");'>{title} (<span style='color: {GetTestColor (test)}'>{state}</span>{buildOnly}) </span>");
|
writer.Write ($"<span id='x{id_counter++}' class='p3 autorefreshable' onclick='javascript: toggleLogVisibility (\"{log_id}\");'>{title} (<span style='color: {GetTestColor (test)}'>{state}</span>{buildOnly}) </span>");
|
||||||
|
}
|
||||||
if (IsServerMode) {
|
if (IsServerMode) {
|
||||||
writer.Write ($" <span id='x{id_counter++}' class='autorefreshable'>");
|
writer.Write ($" <span id='x{id_counter++}' class='autorefreshable'>");
|
||||||
if (test.Waiting) {
|
if (test.Waiting) {
|
||||||
|
|
Двоичные данные
tests/xharness/favicon.ico
Двоичные данные
tests/xharness/favicon.ico
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 3.2 KiB После Ширина: | Высота: | Размер: 3.1 KiB |
|
@ -49,7 +49,7 @@
|
||||||
left: -9999px;
|
left: -9999px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
width: 200px;
|
min-width: 200px;
|
||||||
border-style: ridge;
|
border-style: ridge;
|
||||||
border-width: thin;
|
border-width: thin;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ function quit ()
|
||||||
window.close ();
|
window.close ();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
xhttp.open("GET", "quit", true);
|
xhttp.open("GET", "/quit", true);
|
||||||
xhttp.send();
|
xhttp.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,17 +94,17 @@ function keyhandler(event)
|
||||||
|
|
||||||
function buildtest(id)
|
function buildtest(id)
|
||||||
{
|
{
|
||||||
sendrequest ("build?" + id);
|
sendrequest ("/build?" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function runtest(id)
|
function runtest(id)
|
||||||
{
|
{
|
||||||
sendrequest ("run?" + id);
|
sendrequest ("/run?" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stoptest(id)
|
function stoptest(id)
|
||||||
{
|
{
|
||||||
sendrequest ("stop?" + id);
|
sendrequest ("/stop?" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendrequest(url, callback)
|
function sendrequest(url, callback)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче