Merge remote-tracking branch 'upstream/master' into binary-artifacts

This commit is contained in:
Alexander Köplinger 2019-05-23 20:19:27 +02:00
Родитель 48b3b82410 fc5067ee67
Коммит 776d40550c
13 изменённых файлов: 354 добавлений и 129 удалений

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

@ -93,7 +93,7 @@ namespace CoreServices {
public static CFHTTPMessage CreateEmpty (bool request)
{
var handle = CFHTTPMessageCreateEmpty (IntPtr.Zero, request);
return new CFHTTPMessage (handle);
return new CFHTTPMessage (handle, true);
}
[DllImport (Constants.CFNetworkLibrary)]
@ -110,7 +110,7 @@ namespace CoreServices {
var handle = CFHTTPMessageCreateRequest (
IntPtr.Zero, method.Handle, url.Handle, GetVersion (version));
return new CFHTTPMessage (handle);
return new CFHTTPMessage (handle, true);
}
public static CFHTTPMessage CreateRequest (Uri uri, string method)

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

@ -61,6 +61,8 @@ namespace System.Net.Http {
namespace Foundation {
#endif
public delegate bool NSUrlSessionHandlerTrustOverrideCallback (NSUrlSessionHandler sender, SecTrust trust);
// useful extensions for the class in order to set it in a header
static class NSHttpCookieExtensions
{
@ -291,6 +293,18 @@ namespace Foundation {
}
}
NSUrlSessionHandlerTrustOverrideCallback trustOverride;
public NSUrlSessionHandlerTrustOverrideCallback TrustOverride {
get {
return trustOverride;
}
set {
EnsureModifiability ();
trustOverride = value;
}
}
bool sentRequest;
internal void EnsureModifiability ()
@ -655,7 +669,7 @@ namespace Foundation {
inflight.CancellationTokenSource.Cancel ();
inflight.Errored = true;
var exc = createExceptionForNSError (error);
var exc = inflight.Exception ?? createExceptionForNSError (error);
inflight.CompletionSource.TrySetException (exc);
inflight.Stream.TrySetException (exc);
} else {
@ -705,6 +719,22 @@ namespace Foundation {
if (inflight == null)
return;
// ToCToU for the callback
var trustCallback = sessionHandler.TrustOverride;
if (trustCallback != null && challenge.ProtectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodServerTrust) {
if (trustCallback (sessionHandler, challenge.ProtectionSpace.ServerSecTrust)) {
var credential = new NSUrlCredential (challenge.ProtectionSpace.ServerSecTrust);
completionHandler (NSUrlSessionAuthChallengeDisposition.UseCredential, credential);
} else {
// user callback rejected the certificate, we want to set the exception, else the user will
// see as if the request was cancelled.
lock (inflight.Lock) {
inflight.Exception = new HttpRequestException ("An error occurred while sending the request.", new WebException ("Error: TrustFailure"));
}
completionHandler (NSUrlSessionAuthChallengeDisposition.CancelAuthenticationChallenge, null);
}
return;
}
// case for the basic auth failing up front. As per apple documentation:
// The URL Loading System is designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers using
// the addValue(_:forHTTPHeaderField:) or setValue(_:forHTTPHeaderField:) methods:
@ -717,7 +747,7 @@ namespace Foundation {
// but we are hiding such a situation from our users, we can nevertheless know if the header was added and deal with it. The idea is as follows,
// check if we are in the first attempt, if we are (PreviousFailureCount == 0), we check the headers of the request and if we do have the Auth
// header, it means that we do not have the correct credentials, in any other case just do what it is expected.
if (challenge.PreviousFailureCount == 0) {
var authHeader = inflight.Request?.Headers?.Authorization;
if (!(string.IsNullOrEmpty (authHeader?.Scheme) && string.IsNullOrEmpty (authHeader?.Parameter))) {
@ -783,6 +813,7 @@ namespace Foundation {
public HttpRequestMessage Request { get; set; }
public HttpResponseMessage Response { get; set; }
public Exception Exception { get; set; }
public bool ResponseSent { get; set; }
public bool Errored { get; set; }
public bool Disposed { get; set; }

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

@ -10296,7 +10296,7 @@ namespace AppKit {
void ResetCursorRects ();
[Export ("setToolTip:forCell:")]
void SetToolTipForCell (string toolTipString, NSCell cell);
void SetToolTipForCell ([NullAllowed] string toolTipString, NSCell cell);
[Export ("toolTipForCell:")]
string ToolTipForCell (NSCell cell);

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

@ -0,0 +1,3 @@
# Make OOM on the 32b simulator
System.Threading.Tests.SemaphoreSlimTests.RunSemaphoreSlimTest8_ConcWaitAndRelease(initial: 0, maximum: 1000, waitThreads: 50, releaseThreads: 25, succeededWait: 25, failedWait: 25, finalCount: 0, timeout: 500)
System.Threading.Tests.SemaphoreSlimTests.RunSemaphoreSlimTest8_ConcWaitAndRelease(initial: 5, maximum: 1000, waitThreads: 50, releaseThreads: 50, succeededWait: 50, failedWait: 0, finalCount: 5, timeout: 1000)

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

@ -411,6 +411,7 @@ namespace Xamarin.Tests
$"/p:Configuration={configuration}",
$"/p:Platform={platform}",
$"/verbosity:{(string.IsNullOrEmpty (verbosity) ? "normal" : verbosity)}",
"/r:True", // restore nuget packages which are used in some test cases
project
}.Union (arguments ?? new string [] { }).ToArray (),
environmentVariables: environmentVariables,

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

@ -30,7 +30,9 @@ using UIKit;
#endif
using ObjCRuntime;
#else
using nint=global::System.Int32;
#if MONOMAC
using MonoMac;
using MonoMac.ObjCRuntime;
using MonoMac.Foundation;
using MonoMac.AppKit;
@ -44,6 +46,10 @@ using MonoTouch.UIKit;
partial class TestRuntime
{
[DllImport (Constants.CoreFoundationLibrary)]
public extern static nint CFGetRetainCount (IntPtr handle);
[DllImport ("/usr/lib/system/libdyld.dylib")]
static extern int dyld_get_program_sdk_version ();

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

@ -78,10 +78,10 @@ namespace Introspection {
// not a framework, largely p/invokes to /usr/lib/libSystem.dylib
case "Darwin":
return true;
#endif
// not directly bindings
case "System.Net.Http":
return true;
#endif
default:
return false;
}

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

@ -41,6 +41,7 @@ namespace MonoTouchFixtures.CoreServices {
Assert.Throws<InvalidOperationException> (delegate { var x = m.ResponseStatusCode; }, "ResponseStatusCode");
Assert.Throws<InvalidOperationException> (delegate { var x = m.ResponseStatusLine; }, "ResponseStatusLine");
Assert.That (m.Version.ToString (), Is.EqualTo ("1.1"), "Version");
Assert.That (TestRuntime.CFGetRetainCount (m.Handle), Is.EqualTo ((nint) 1), "RetainCount");
}
}
@ -54,6 +55,7 @@ namespace MonoTouchFixtures.CoreServices {
Assert.That (m.ResponseStatusCode, Is.EqualTo (HttpStatusCode.OK), "ResponseStatusCode");
Assert.That (m.ResponseStatusLine, Is.Empty, "ResponseStatusLine");
Assert.That (m.Version.ToString (), Is.EqualTo ("1.1"), "Version");
Assert.That (TestRuntime.CFGetRetainCount (m.Handle), Is.EqualTo ((nint)1), "RetainCount");
}
}
@ -67,6 +69,7 @@ namespace MonoTouchFixtures.CoreServices {
Assert.Throws<InvalidOperationException> (delegate { var x = m.ResponseStatusCode; }, "ResponseStatusCode");
Assert.Throws<InvalidOperationException> (delegate { var x = m.ResponseStatusLine; }, "ResponseStatusLine");
Assert.That (m.Version.ToString (), Is.EqualTo ("1.0"), "Version");
Assert.That (TestRuntime.CFGetRetainCount (m.Handle), Is.EqualTo ((nint)1), "RetainCount");
}
}
}

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

@ -159,5 +159,112 @@ namespace MonoTests.System.Net.Http
Assert.IsNull (ex, $"Exception {ex} for {json}");
}
}
#if !__WATCHOS__
[TestCase (typeof (HttpClientHandler))]
#endif
[TestCase (typeof (NSUrlSessionHandler))]
public void RejectSslCertificatesServicePointManager (Type handlerType)
{
TestRuntime.AssertSystemVersion (PlatformName.MacOSX, 10, 9, throwIfOtherPlatform: false);
TestRuntime.AssertSystemVersion (PlatformName.iOS, 7, 0, throwIfOtherPlatform: false);
bool servicePointManagerCbWasExcuted = false;
bool done = false;
Exception ex = null;
var handler = GetHandler (handlerType);
if (handler is NSUrlSessionHandler ns) {
ns.TrustOverride += (a,b) => {
servicePointManagerCbWasExcuted = true;
// return false, since we want to test that the exception is raised
return false;
};
} else {
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => {
servicePointManagerCbWasExcuted = true;
// return false, since we want to test that the exception is raised
return false;
};
}
TestRuntime.RunAsync (DateTime.Now.AddSeconds (30), async () =>
{
try {
HttpClient client = new HttpClient (handler);
client.BaseAddress = new Uri ("https://httpbin.org");
var byteArray = new UTF8Encoding ().GetBytes ("username:password");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Basic", Convert.ToBase64String(byteArray));
var result = await client.GetAsync ("https://httpbin.org/redirect/3");
} catch (Exception e) {
ex = e;
} finally {
done = true;
ServicePointManager.ServerCertificateValidationCallback = null;
}
}, () => done);
if (!done) { // timeouts happen in the bost due to dns issues, connection issues etc.. we do not want to fail
Assert.Inconclusive ("Request timedout.");
} else {
// assert the exception type
Assert.IsInstanceOfType (typeof (HttpRequestException), ex);
Assert.IsNotNull (ex.InnerException);
Assert.IsInstanceOfType (typeof (WebException), ex.InnerException);
}
}
#if !__WATCHOS__
[TestCase (typeof (HttpClientHandler))]
#endif
[TestCase (typeof (NSUrlSessionHandler))]
public void AcceptSslCertificatesServicePointManager (Type handlerType)
{
TestRuntime.AssertSystemVersion (PlatformName.MacOSX, 10, 9, throwIfOtherPlatform: false);
TestRuntime.AssertSystemVersion (PlatformName.iOS, 7, 0, throwIfOtherPlatform: false);
bool servicePointManagerCbWasExcuted = false;
bool done = false;
Exception ex = null;
var handler = GetHandler (handlerType);
if (handler is NSUrlSessionHandler ns) {
ns.TrustOverride += (a,b) => {
servicePointManagerCbWasExcuted = true;
return true;
};
} else {
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => {
servicePointManagerCbWasExcuted = true;
return true;
};
}
TestRuntime.RunAsync (DateTime.Now.AddSeconds (30), async () =>
{
try {
HttpClient client = new HttpClient (handler);
client.BaseAddress = new Uri ("https://httpbin.org");
var byteArray = new UTF8Encoding ().GetBytes ("username:password");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Basic", Convert.ToBase64String(byteArray));
var result = await client.GetAsync ("https://httpbin.org/redirect/3");
} catch (Exception e) {
ex = e;
} finally {
done = true;
ServicePointManager.ServerCertificateValidationCallback = null;
}
}, () => done);
if (!done) { // timeouts happen in the bost due to dns issues, connection issues etc.. we do not want to fail
Assert.Inconclusive ("Request timedout.");
} else {
// assert that we did not get an exception
if (ex != null && ex.InnerException != null) {
// we could get here.. if we have a diff issue, in that case, lets get the exception message and assert is not the trust issue
Assert.AreNotEqual (ex.InnerException.Message, "Error: TrustFailure");
}
}
}
}
}

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

@ -2554,7 +2554,7 @@ public class B
[TestCase (Target.Dev, Profile.iOS, "link sdk", "Release64")]
[TestCase (Target.Dev, Profile.iOS, "monotouch-test", "Release64")]
[TestCase (Target.Dev, Profile.iOS, "mscorlib", "Release64")]
[TestCase (Target.Dev, Profile.iOS, "System.Data", "Release64")]
[TestCase (Target.Dev, Profile.iOS, "BCL tests group 1", "Release64")]
public void BuildTestProject (Target target, Profile profile, string testname, string configuration)
{
if (target == Target.Dev)
@ -2569,12 +2569,20 @@ public class B
break;
case "monotouch-test":
break;
default:
case "mscorlib":
subdir = "/bcl-test";
break;
default:
subdir = "/bcl-test/BCLTests";
break;
}
var platform = target == Target.Dev ? "iPhone" : "iPhoneSimulator";
var csproj = Path.Combine (Configuration.SourceRoot, "tests" + subdir, testname, testname + GetProjectSuffix (profile) + ".csproj");
string csproj = null;
if (subdir == "/bcl-test/BCLTests") { // bcl tests are generated and are not in their own dir
csproj = Path.Combine (Configuration.SourceRoot, "tests" + subdir, testname + GetProjectSuffix (profile) + ".csproj");
} else {
csproj = Path.Combine (Configuration.SourceRoot, "tests" + subdir, testname, testname + GetProjectSuffix (profile) + ".csproj");
}
XBuild.BuildXI (csproj, configuration, platform, timeout: TimeSpan.FromMinutes (15));
}

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

@ -326,168 +326,226 @@ namespace xharness
}
}
bool IsTouchUnitResult (XmlDocument log)
bool IsTouchUnitResult (StreamReader stream)
{
return log.SelectSingleNode ("/TouchUnitTestRun/NUnitOutput") != null;
}
XmlDocument ParseTouchUnitXml (XmlDocument log, StreamWriter writer)
{
var nunit_output = log.SelectSingleNode ("/TouchUnitTestRun/NUnitOutput");
var nunitXml = new XmlDocument ();
nunitXml.LoadXml (nunit_output.InnerXml);
writer.Write (log.SelectSingleNode ("/TouchUnitTestRun/TouchUnitExtraData").InnerText);
return nunitXml;
}
XmlDocument ParseNUnitXml (XmlDocument log, StreamWriter writer)
{
var str = log.InnerXml;
var resultsNode = log.SelectSingleNode ("test-results");
// parse the xml and build a human readable version
int total = int.Parse (resultsNode.Attributes ["total"].InnerText);
int errors = int.Parse (resultsNode.Attributes ["errors"].InnerText);
int failed = int.Parse (resultsNode.Attributes ["failures"].InnerText);
int notRun = int.Parse (resultsNode.Attributes ["not-run"].InnerText);
int inconclusive = int.Parse (resultsNode.Attributes ["inconclusive"].InnerText);
int ignored = int.Parse (resultsNode.Attributes ["ignored"].InnerText);
int skipped = int.Parse (resultsNode.Attributes ["skipped"].InnerText);
int invalid = int.Parse (resultsNode.Attributes ["invalid"].InnerText);
int passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
var testFixtures = resultsNode.SelectNodes ("//test-suite[@type='TestFixture' or @type='TestCollection']");
for (var i = 0; i < testFixtures.Count; i++) {
var node = testFixtures [i];
writer.WriteLine (node.Attributes ["name"].InnerText);
var testCases = node.SelectNodes ("//test-case");
for (var j = 0; j < testCases.Count; j++) {
var result = testCases [j];
var status = result.Attributes ["result"].InnerText;
switch (status) {
case "Success":
writer.Write ("\t[PASS] ");
break;
case "Ignored":
writer.Write ("\t[IGNORED] ");
break;
case "Error":
case "Failure":
writer.Write ("\t[FAIL] ");
break;
case "Inconclusive":
writer.Write ("\t[INCONCLUSIVE] ");
break;
default:
writer.Write ("\t[INFO] ");
// TouchUnitTestRun is the very first node in the TouchUnit xml result
// which is not preset in the xunit xml, therefore we know the runner
// quite quickly
bool isTouchUnit = false;
using (var reader = XmlReader.Create (stream)) {
while (reader.Read ()) {
if (reader.NodeType == XmlNodeType.Element && reader.Name == "TouchUnitTestRun") {
isTouchUnit = true;
break;
}
writer.Write (result.Attributes ["name"].InnerText);
if (status == "Failure" || status == "Error") { // we need to print the message
writer.Write ($" : {result.InnerText}");
}
// add a new line
writer.WriteLine ();
}
var time = node.Attributes ["time"]?.InnerText ?? "0"; // some nodes might not have the time :/
writer.WriteLine ($"{node.Attributes ["name"].InnerXml} {time} ms");
}
writer.WriteLine ($"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}");
return log;
// we want to reuse the stream (and we are sync)
stream.BaseStream.Position = 0;
stream.DiscardBufferedData ();
return isTouchUnit;
}
public bool TestsSucceeded (Log listener_log, bool timed_out, bool crashed)
(string resultLine, bool failed) ParseTouchUnitXml (StreamReader stream, StreamWriter writer)
{
long total, errors, failed, notRun, inconclusive, ignored, skipped, invalid;
total = errors = failed = notRun = inconclusive = ignored = skipped = invalid = 0L;
using (var reader = XmlReader.Create (stream)) {
while (reader.Read ()) {
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-results") {
total = long.Parse (reader ["total"]);
errors = long.Parse (reader ["errors"]);
failed = long.Parse (reader ["failures"]);
notRun = long.Parse (reader ["not-run"]);
inconclusive = long.Parse (reader ["inconclusive"]);
ignored = long.Parse (reader ["ignored"]);
skipped = long.Parse (reader ["skipped"]);
invalid = long.Parse (reader ["invalid"]);
}
if (reader.NodeType == XmlNodeType.Element && reader.Name == "TouchUnitExtraData") {
// move fwd to get to the CData
if (reader.Read ())
writer.Write (reader.Value);
}
}
}
var passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
var resultLine = $"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}";
return (resultLine, errors != 0 && failed != 0);
}
(string resultLine, bool failed) ParseNUnitXml (StreamReader stream, StreamWriter writer)
{
long total, errors, failed, notRun, inconclusive, ignored, skipped, invalid;
total = errors = failed = notRun = inconclusive = ignored = skipped = invalid = 0L;
using (var reader = XmlReader.Create (stream)) {
while (reader.Read ()) {
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-results") {
total = long.Parse (reader ["total"]);
errors = long.Parse (reader ["errors"]);
failed = long.Parse (reader ["failures"]);
notRun = long.Parse (reader ["not-run"]);
inconclusive = long.Parse (reader ["inconclusive"]);
ignored = long.Parse (reader ["ignored"]);
skipped = long.Parse (reader ["skipped"]);
invalid = long.Parse (reader ["invalid"]);
}
if (reader.NodeType == XmlNodeType.Element && reader.Name == "test-suite" && (reader["type"] == "TestFixture" || reader["type"] == "TestCollection")) {
var testCaseName = reader ["name"];
writer.WriteLine (testCaseName);
var time = reader.GetAttribute ("time") ?? "0"; // some nodes might not have the time :/
// get the first node and then move in the siblings of the same type
reader.ReadToDescendant ("test-case");
do {
if (reader.Name != "test-case")
break;
// read the test cases in the current node
var status = reader ["result"];
switch (status) {
case "Success":
writer.Write ("\t[PASS] ");
break;
case "Ignored":
writer.Write ("\t[IGNORED] ");
break;
case "Error":
case "Failure":
writer.Write ("\t[FAIL] ");
break;
case "Inconclusive":
writer.Write ("\t[INCONCLUSIVE] ");
break;
default:
writer.Write ("\t[INFO] ");
break;
}
writer.Write (reader ["name"]);
if (status == "Failure" || status == "Error") { // we need to print the message
writer.Write ($" : {reader.ReadElementContentAsString ()}");
}
// add a new line
writer.WriteLine ();
} while (reader.ReadToNextSibling ("test-case"));
writer.WriteLine ($"{testCaseName} {time} ms");
}
}
}
var passed = total - errors - failed - notRun - inconclusive - ignored - skipped - invalid;
string resultLine = $"Tests run: {total} Passed: {passed} Inconclusive: {inconclusive} Failed: {failed + errors} Ignored: {ignored + skipped + invalid}";
writer.WriteLine (resultLine);
return (resultLine, errors != 0 && failed != 0);
}
(string resultLine, bool failed, bool crashed) ParseResult (Log listener_log, bool timed_out, bool crashed)
{
if (!File.Exists (listener_log.FullPath))
return (null, false, true); // if we do not have a log file, the test crashes
// parsing the result is different if we are in jenkins or not.
// When in Jenkins, Touch.Unit produces an xml file instead of a console log (so that we can get better test reporting).
// However, for our own reporting, we still want the console-based log. This log is embedded inside the xml produced
// by Touch.Unit, so we need to extract it and write it to disk. We also need to re-save the xml output, since Touch.Unit
// wraps the NUnit xml output with additional information, which we need to unwrap so that Jenkins understands it.
//
// On the other hand, the nunit and xunit do not have that data and have to be parsed.
if (Harness.InJenkins) {
// use a tmp file so that we can use the reader in xml and write the humman version
var tmpFile = Path.GetTempFileName ();
// we have to parse the xml result
(string resultLine, bool failed, bool crashed) parseResult = (null, false, false);
// move the xml to a tmp path, that path will be use to read the xml
// in the reader, and the writer will use the stream from the logger to
// write the human readable log
var tmpFile = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
File.Move (listener_log.FullPath, tmpFile);
crashed = false;
var xmldoc = new XmlDocument ();
XmlNode mainResultNode;
try {
using (var reader = listener_log.GetReader ()) {
xmldoc.Load (reader);
var testsResults = new XmlDocument ();
using (var writer = new StreamWriter (tmpFile)) {
if (IsTouchUnitResult (xmldoc)) {
testsResults = ParseTouchUnitXml (xmldoc, writer);
using (var streamReaderTmp = new StreamReader (tmpFile)) {
var isTouchUnit = IsTouchUnitResult (streamReaderTmp); // method resets position
using (var writer = new StreamWriter (listener_log.FullPath, true)) { // write the human result to the log file
if (isTouchUnit) {
var (resultLine, failed)= ParseTouchUnitXml (streamReaderTmp, writer);
parseResult.resultLine = resultLine;
parseResult.failed = failed;
} else {
testsResults = ParseNUnitXml (xmldoc, writer);
var (resultLine, failed)= ParseNUnitXml (streamReaderTmp, writer);
parseResult.resultLine = resultLine;
parseResult.failed = failed;
}
}
mainResultNode = testsResults.SelectSingleNode ("test-results");
}
if (mainResultNode == null) {
Harness.LogWrench ($"Node is null.");
} else {
// update the information of the main node to add information about the mode and the test that is excuted. This will later create
// nicer reports in jenkins
mainResultNode.Attributes ["name"].Value = Target.AsString ();
// store a clean version of the logs, later this will be used by the bots to show results in github/web
// reset pos of the stream
streamReaderTmp.BaseStream.Position = 0;
streamReaderTmp.DiscardBufferedData ();
var path = listener_log.FullPath;
path = Path.ChangeExtension (path, "xml");
// we already have all the data needed in the listerner, rather than saving from the doc, copy
File.Copy (listener_log.FullPath, path, true);
// both the nunit and xunit runners are not
// setting the test results correctly, lets add them
using (var xmlWriter = new StreamWriter (path)) {
string line;
while ((line = streamReaderTmp.ReadLine ()) != null) {
if (line.Contains ("<test-results")) {
if (line.Contains ("name=\"\"")) { // NUnit case
xmlWriter.WriteLine (line.Replace ("name=\"\"", $"name=\"{appName + " " + configuration}\""));
xmlWriter.WriteLine (line);
} else if (line.Contains ($"name=\"com.xamarin.bcltests.{appName}\"")) { // xunit case
xmlWriter.WriteLine (line.Replace ($"name=\"com.xamarin.bcltests.{appName}\"", $"name=\"{appName + " " + configuration}\""));
}
} else {
xmlWriter.WriteLine (line);
}
}
}
// we do not longer need the tmp file
Logs.AddFile (path, "Test xml");
}
// write on the log
File.Copy (tmpFile, listener_log.FullPath, true);
File.Delete (tmpFile);
return parseResult;
} catch (Exception e) {
main_log.WriteLine ("Could not parse xml result file: {0}", e);
if (timed_out) {
Harness.LogWrench ($"@MonkeyWrench: AddSummary: <b><i>{mode} timed out</i></b><br/>");
return false;
return parseResult;
} else {
Harness.LogWrench ($"@MonkeyWrench: AddSummary: <b><i>{mode} crashed</i></b><br/>");
main_log.WriteLine ("Test run crashed");
crashed = true;
return false;
parseResult.crashed = true;
return parseResult;
}
} finally {
if (File.Exists (tmpFile))
File.Delete (tmpFile);
}
}
// read until the end and decide if we got results, do not store them
// we do not want to use too much memory
string resultLine = null;
using (var reader = new StreamReader (listener_log.FullPath)) {
string line;
while ((line = reader.ReadLine ()) != null)
{
if (line.Contains ("Tests run"))
resultLine = line;
}
}
// read the parsed logs in a human readable way
if (resultLine != null) {
var tests_run = string.Empty;
var failed = false;
using (var reader = listener_log.GetReader () ) {
string line;
} else {
// not the most efficient way but this just happens when we run
// the tests locally and we usually do not run all tests, we are
// more interested to be efficent on the bots
string resultLine = null;
using (var reader = new StreamReader (listener_log.FullPath)) {
string line = null;
bool failed = false;
while ((line = reader.ReadLine ()) != null)
{
if (line.Contains ("Tests run:")) {
Console.WriteLine (line);
tests_run = line.Replace ("Tests run: ", "");
resultLine = line;
break;
} else if (line.Contains ("[FAIL]")) {
Console.WriteLine (line);
failed = true;
}
}
return (resultLine, failed, false);
}
}
}
public bool TestsSucceeded (Log listener_log, bool timed_out, bool crashed)
{
var (resultLine, failed, crashed_out) = ParseResult (listener_log, timed_out, crashed);
var tests_run = resultLine.Replace ("Tests run: ", "");
// read the parsed logs in a human readable way
if (resultLine != null) {
if (failed) {
Harness.LogWrench ("@MonkeyWrench: AddSummary: <b>{0} failed: {1}</b><br/>", mode, tests_run);
main_log.WriteLine ("Test run failed");

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

@ -305,7 +305,8 @@ namespace xharness
}
break;
case "mscorlib":
yield return new TestData { Variation = "Debug: SGenConc", MTouchExtraArgs = "", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, EnableSGenConc = true};
if (supports_debug)
yield return new TestData { Variation = "Debug: SGenConc", MTouchExtraArgs = "", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, EnableSGenConc = true};
if (supports_interpreter) {
if (supports_debug) {
yield return new TestData { Variation = "Debug (interpreter)", MTouchExtraArgs = "--interpreter", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME" };
@ -315,7 +316,8 @@ namespace xharness
}
break;
case "mini":
yield return new TestData { Variation = "Debug: SGenConc", MTouchExtraArgs = "", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, EnableSGenConc = true};
if (supports_debug)
yield return new TestData { Variation = "Debug: SGenConc", MTouchExtraArgs = "", Debug = true, Profiling = false, MonoNativeLinkMode = MonoNativeLinkMode.Static, EnableSGenConc = true};
if (supports_interpreter) {
if (supports_debug) {
yield return new TestData { Variation = "Debug (interpreter)", MTouchExtraArgs = "--interpreter", Debug = true, Profiling = false, Undefines = "FULL_AOT_RUNTIME" };
@ -1770,7 +1772,10 @@ namespace xharness
markdown_summary.Write ($"# Test run in progress: ");
markdown_summary.Write (string.Join (", ", list));
} else if (failedTests.Any ()) {
markdown_summary.Write ($"{failedTests.Count ()} tests failed, {deviceNotFound.Count ()} tests' device not found, {passedTests.Count ()} tests passed.");
markdown_summary.Write ($"{failedTests.Count ()} tests failed, ");
if (deviceNotFound.Any ())
markdown_summary.Write ($"{deviceNotFound.Count ()} tests' device not found, ");
markdown_summary.Write ($"{passedTests.Count ()} tests passed.");
} else if (deviceNotFound.Any ()) {
markdown_summary.Write ($"{deviceNotFound.Count ()} tests' device not found, {passedTests.Count ()} tests passed.");
} else if (passedTests.Any ()) {
@ -1854,7 +1859,10 @@ namespace xharness
writer.Write (string.Join (", ", list));
writer.Write (")");
} else if (failedTests.Any ()) {
writer.Write ($"{failedTests.Count ()} tests failed, {deviceNotFound.Count ()} tests' device not found, {passedTests.Count ()} tests passed");
writer.Write ($"{failedTests.Count ()} tests failed, ");
if (deviceNotFound.Any ())
writer.Write ($"{deviceNotFound.Count ()} tests' device not found, ");
writer.Write ($"{passedTests.Count ()} tests passed");
} else if (deviceNotFound.Any ()) {
writer.Write ($"{deviceNotFound.Count ()} tests' device not found, {passedTests.Count ()} tests passed");
} else if (passedTests.Any ()) {

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

@ -154,7 +154,7 @@ namespace xharness
XmlDocument info_plist = new XmlDocument ();
var target_info_plist = Path.Combine (TargetDirectory, $"Info{Suffix}-extension.plist");
info_plist.LoadWithoutNetworkAccess (Path.Combine (TargetDirectory, "Info.plist"));
BundleIdentifier = info_plist.GetCFBundleIdentifier () + "-watch";
BundleIdentifier = info_plist.GetCFBundleIdentifier () + "_watch";
if (BundleIdentifier.Length >= 58)
BundleIdentifier = BundleIdentifier.Substring (0, 57); // If the main app's bundle id is 58 characters (or sometimes more), then the watch extension crashes at launch. radar #29847128.
info_plist.SetCFBundleIdentifier (BundleIdentifier + ".watchkitapp.watchkitextension");