[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:
Rolf Bjarne Kvinge 2019-06-12 16:47:15 +02:00 коммит произвёл GitHub
Родитель 6a852fdcc2
Коммит d3c60e516b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 106 добавлений и 42 удалений

Просмотреть файл

@ -1300,7 +1300,7 @@ namespace xharness
break;
case "/set-option":
response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
switch (request.Url.Query) {
switch (request.Url.Query) {
case "?clean":
CleanSuccessfulTestRuns = true;
break;
@ -1481,17 +1481,21 @@ namespace xharness
server.Stop ();
break;
case "/favicon.ico":
var favicon = File.ReadAllBytes (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));
serveFile = Path.Combine (Harness.RootDirectory, "xharness", "favicon.ico");
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:
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)
serveFile = Path.Combine (LogDirectory, request.Url.LocalPath.Substring (1));
serveFile = Path.Combine (Path.GetDirectoryName (LogDirectory), request.Url.LocalPath.Substring (1));
var path = serveFile;
if (File.Exists (path)) {
var buffer = new byte [4096];
@ -1508,6 +1512,9 @@ namespace xharness
case ".js":
response.ContentType = "text/javascript";
break;
case ".ico":
response.ContentType = "image/png";
break;
default:
response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
break;
@ -1516,6 +1523,7 @@ namespace xharness
response.OutputStream.Write (buffer, 0, read);
}
} else {
Console.WriteLine ($"404: {request.Url.LocalPath}");
response.StatusCode = 404;
response.OutputStream.WriteByte ((byte) '?');
}
@ -1535,7 +1543,7 @@ namespace xharness
};
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.");
Process.Start ("open", url);
@ -1636,12 +1644,31 @@ namespace xharness
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 (Harness.RootDirectory, "xharness", "favicon.ico"), Path.Combine (LogDirectory, "favicon.ico"), true);
}
} catch (Exception 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)
{
var id_counter = 0;
@ -1819,7 +1846,7 @@ namespace xharness
} else {
writer.Write ($"No tests selected.");
}
writer.WriteLine ("</span>");
writer.Write ("</span>");
writer.WriteLine ("</h2>");
if (allTasks.Count > 0) {
writer.WriteLine ($"<ul id='nav'>");
@ -1827,34 +1854,34 @@ namespace xharness
writer.WriteLine (@"
<li>Select
<ul>
<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-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-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-mac"");'>All Mac 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-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-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-mac"");'>All Mac tests</a></li>
</ul>
</li>
<li>Deselect
<ul>
<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-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-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-mac"");'>All Mac 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-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-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-mac"");'>All Mac tests</a></li>
</ul>
</li>
<li>Execute
<ul>
<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?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?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 (""/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?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?selected"");'>Build all selected tests</a></li>
<li class=""adminitem""><a href='javascript:sendrequest (""/build?failed"");'>Build all failed tests</a></li>
</ul>
</li>");
}
@ -1870,19 +1897,51 @@ namespace xharness
writer.WriteLine ($@"
<li>Reload
<ul>
<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-devices"");'>Devices</a></li>
<li class=""adminitem""><a href='javascript:sendrequest (""/reload-simulators"");'>Simulators</a></li>
</ul>
</li>
<li>Options
<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?{(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?{(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?{(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>
</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>");
}
@ -1974,7 +2033,12 @@ namespace xharness
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='x{id_counter++}' class='p3 autorefreshable' onclick='javascript: toggleLogVisibility (\"{log_id}\");'>{title} (<span style='color: {GetTestColor (test)}'>{state}</span>{buildOnly}) </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>");
}
if (IsServerMode) {
writer.Write ($" <span id='x{id_counter++}' class='autorefreshable'>");
if (test.Waiting) {

Двоичные данные
tests/xharness/favicon.ico

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

После

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Просмотреть файл

@ -49,7 +49,7 @@
left: -9999px;
padding: 10px;
z-index: 2;
width: 200px;
min-width: 200px;
border-style: ridge;
border-width: thin;
}

Просмотреть файл

@ -46,7 +46,7 @@ function quit ()
window.close ();
}
};
xhttp.open("GET", "quit", true);
xhttp.open("GET", "/quit", true);
xhttp.send();
}
@ -94,17 +94,17 @@ function keyhandler(event)
function buildtest(id)
{
sendrequest ("build?" + id);
sendrequest ("/build?" + id);
}
function runtest(id)
{
sendrequest ("run?" + id);
sendrequest ("/run?" + id);
}
function stoptest(id)
{
sendrequest ("stop?" + id);
sendrequest ("/stop?" + id);
}
function sendrequest(url, callback)