Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the parameters to VSTestTask to allow dotnet test to work #2438

Merged
2 commits merged into from
May 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ Copyright (c) .NET Foundation. All rights reserved.
VSTestVerbosity="$(VSTestVerbosity)"
VSTestCollect="$(VSTestCollect)"
VSTestBlame="$(VSTestBlame)"
VSTestBlameCrash="$(VSTestBlameCrash)"
VSTestBlameCrashDumpType="$(VSTestBlameCrashDumpType)"
VSTestBlameCrashCollectAlways="$(VSTestBlameCrashCollectAlways)"
VSTestBlameHang="$(VSTestBlameHang)"
VSTestBlameHangDumpType="$(VSTestBlameHangDumpType)"
VSTestBlameHangTimeout="$(VSTestBlameHangTimeout)"
VSTestTraceDataCollectorDirectoryPath="$(TraceDataCollectorDirectoryPath)"
VSTestNoLogo="$(VSTestNoLogo)"
Condition="'$(IsTestProject)' == 'true'"
Expand Down
88 changes: 83 additions & 5 deletions src/Microsoft.TestPlatform.Build/Tasks/VSTestTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Microsoft.TestPlatform.Build.Tasks
{
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.TestPlatform.Build.Resources;
Expand Down Expand Up @@ -108,6 +109,41 @@ public string VSTestBlame
set;
}

public string VSTestBlameCrash
{
get;
set;
}

public string VSTestBlameCrashDumpType
{
get;
set;
}

public string VSTestBlameCrashCollectAlways
{
get;
set;
}

public string VSTestBlameHang
{
get;
set;
}

public string VSTestBlameHangDumpType
{
get;
set;
}
public string VSTestBlameHangTimeout
{
get;
set;
}

public string VSTestTraceDataCollectorDirectoryPath
{
get;
Expand Down Expand Up @@ -242,8 +278,8 @@ private List<string> AddArgs()
// Console logger was not specified by user, but verbosity was, hence add default console logger with verbosity as specified
if (!string.IsNullOrWhiteSpace(this.VSTestVerbosity) && !isConsoleLoggerSpecifiedByUser)
{
var normalTestLogging = new List<string>() {"n", "normal", "d", "detailed", "diag", "diagnostic"};
var quietTestLogging = new List<string>() {"q", "quiet"};
var normalTestLogging = new List<string>() { "n", "normal", "d", "detailed", "diag", "diagnostic" };
var quietTestLogging = new List<string>() { "q", "quiet" };

string vsTestVerbosity = "minimal";
if (normalTestLogging.Contains(this.VSTestVerbosity.ToLowerInvariant()))
Expand All @@ -258,9 +294,51 @@ private List<string> AddArgs()
allArgs.Add("--logger:Console;Verbosity=" + vsTestVerbosity);
}

if (!string.IsNullOrEmpty(this.VSTestBlame))
var blameCrash = !string.IsNullOrEmpty(this.VSTestBlameCrash);
var blameHang = !string.IsNullOrEmpty(this.VSTestBlameHang);
if (!string.IsNullOrEmpty(this.VSTestBlame) || blameCrash || blameHang)
{
allArgs.Add("--Blame");
var blameArgs = "--Blame";

var dumpArgs = new List<string>();
if (blameCrash || blameHang)
{
if (blameCrash)
{
dumpArgs.Add("CollectDump");
nohwnd marked this conversation as resolved.
Show resolved Hide resolved
if (!string.IsNullOrEmpty(this.VSTestBlameCrashCollectAlways))
{
dumpArgs.Add($"CollectAlways={this.VSTestBlameCrashCollectAlways}");
}

if (!string.IsNullOrEmpty(this.VSTestBlameCrashDumpType))
{
dumpArgs.Add($"DumpType={this.VSTestBlameCrashDumpType}");
}
}

if (blameHang)
{
dumpArgs.Add("CollectHangDump");

if (!string.IsNullOrEmpty(this.VSTestBlameHangDumpType))
{
dumpArgs.Add($"HangDumpType={this.VSTestBlameHangDumpType}");
}

if (!string.IsNullOrEmpty(this.VSTestBlameHangTimeout))
{
dumpArgs.Add($"TestTimeout={this.VSTestBlameHangTimeout}");
}
}

if (dumpArgs.Any())
{
blameArgs += $":\"{string.Join(";", dumpArgs)}\"";
}
}

allArgs.Add(blameArgs);
}

if (this.VSTestCollect != null && this.VSTestCollect.Length > 0)
Expand Down Expand Up @@ -302,7 +380,7 @@ private List<string> AddArgs()
}
}

if(!string.IsNullOrWhiteSpace(this.VSTestNoLogo))
if (!string.IsNullOrWhiteSpace(this.VSTestNoLogo))
{
allArgs.Add("--nologo");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Text.RegularExpressions;

namespace Microsoft.VisualStudio.TestPlatform.Utilities
{
public static class TimeSpanParser
{
static readonly Regex pattern = new Regex(@"(?<value>^\d+(?:\.\d+)?)\s*(?<suffix>ms|mil|m|h|d|s?[a-z]*)$", RegexOptions.IgnoreCase);

public static TimeSpan Parse(string time)
{
return TryParse(time, out var result) ? result : throw GetFormatException(time);
}

public static bool TryParse(string time, out TimeSpan result)
{
if (string.IsNullOrWhiteSpace(time))
{
result = TimeSpan.Zero;
return true;
}

var match = pattern.Match(time);
if (!match.Success)
{
result = TimeSpan.Zero;
return false;
}

var value = match.Groups["value"].Value;
if (!double.TryParse(value, out var number))
{
throw GetFormatException(value);
}

var suffix = match.Groups["suffix"].Value;
var c = StringComparison.OrdinalIgnoreCase;

// mil to distinguish milliseconds from minutes
// "" when there is just the raw milliseconds value
if (suffix.StartsWith("ms", c) || suffix.StartsWith("mil", c) || suffix == string.Empty)
nohwnd marked this conversation as resolved.
Show resolved Hide resolved
{
result = TimeSpan.FromMilliseconds(number);
return true;
}

if (suffix.StartsWith("s", c))
{
result = TimeSpan.FromSeconds(number);
return true;
}

if (suffix.StartsWith("m", c))
{
result = TimeSpan.FromMinutes(number);
return true;
}

if (suffix.StartsWith("h", c))
{
result = TimeSpan.FromHours(number);
return true;
}

if (suffix.StartsWith("d", c))
{
result = TimeSpan.FromDays(number);
return true;
}

result = TimeSpan.Zero;
return false;
}

static FormatException GetFormatException(string value)
{
return new FormatException($"The value '{value}' is not a valid time string. Use a time string in this format 5400000 / 5400000ms / 5400s / 90m / 1.5h / 0.625d.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,9 @@ private void ValidateAndAddHangBasedProcessDumpParameters(XmlElement collectDump
{
case XmlAttribute attribute when string.Equals(attribute.Name, Constants.TestTimeout, StringComparison.OrdinalIgnoreCase):

if (!string.IsNullOrWhiteSpace(attribute.Value) && int.TryParse(attribute.Value, out int inactivityTimespanInMilliseconds))
if (!string.IsNullOrWhiteSpace(attribute.Value) && TimeSpanParser.TryParse(attribute.Value, out var timeout))
{
this.inactivityTimespan = TimeSpan.FromMilliseconds(inactivityTimespanInMilliseconds);
this.inactivityTimespan = timeout;
}
else
{
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,6 @@
<value>CollectDump was enabled but dump file was not generated.</value>
</data>
<data name="UnexpectedValueForInactivityTimespanValue" xml:space="preserve">
<value>Unexpected value {0} provided for ExpectedExecutionTimeOfLongestRunningTestInMinutes. Please provide a positive integer as input.</value>
<value>Unexpected value '{0}' provided as timeout. Please provide a value in this format: 1.5h / 90m / 5400s / 5400000ms / 5400000</value>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace TestPlatform.CoreUtilities.UnitTests
{
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

[TestClass]
public class TimeSpanParserTests
{
[TestMethod]
// core use cases
[DataRow("5400000")]
[DataRow("5400000ms")]
[DataRow("5400s")]
[DataRow("90m")]
[DataRow("1.5h")]
[DataRow("0.0625d")]

// with space for parsing from xml
[DataRow("5400000 ms")]
[DataRow("5400 s")]
[DataRow("90 m")]
[DataRow("1.5 h")]
[DataRow("0.0625 d")]

// nice to haves
[DataRow("5400000MS")]
[DataRow("5400000millisecond")]
[DataRow("5400000milliseconds")]
[DataRow("5400000mil")]
[DataRow("5400000milisecond")]
[DataRow("5400000miliseconds")]
[DataRow("5400000mils")]
[DataRow("5400000millis")]
[DataRow("5400000millisecs")]
[DataRow("5400000milisecs")]
[DataRow("5400S")]
[DataRow("5400second")]
[DataRow("5400seconds")]
[DataRow("5400sec")]
[DataRow("5400secs")]
[DataRow("90M")]
[DataRow("90minute")]
[DataRow("90minutes")]
[DataRow("90min")]
[DataRow("90mins")]
[DataRow("1.5H")]
[DataRow("1.5hour")]
[DataRow("1.5hours")]
[DataRow("1.5hrs")]
[DataRow("1.5hr")]
[DataRow("0.0625D")]
[DataRow("0.0625day")]
[DataRow("0.0625days")]
public void Parses90Minutes(string time)
{
Assert.IsTrue(TimeSpanParser.TryParse(time, out var t));
Assert.AreEqual(TimeSpan.FromMinutes(90), t);
}

[TestMethod]
[DataRow(null)]
[DataRow("")]
[DataRow(" ")]
[DataRow("\n")]
[DataRow("\t")]
public void ReturnsEmptyTimeSpanOnNullOrWhiteSpace(string time)
{
Assert.IsTrue(TimeSpanParser.TryParse(time, out var t));
Assert.AreEqual(TimeSpan.Zero, t);
}

[TestMethod]
[DataRow("09808asf")]
[DataRow("asfsadf")]
[DataRow("min")]
[DataRow("ms")]
[DataRow("1.1.1")]
public void ReturnsFalseForInvalidInput(string time)
{
Assert.IsFalse(TimeSpanParser.TryParse(time, out var _));
}
}
}