Remove StreamForwarder from CLI tests (#4936)
* WiP * Replace StreamForwarder with OutputDataReceived * Add build logging around test execution * add newlines * Add handling for the null terminator while maintaining empty lines * Extra Diag * Verbose logging for VS Test Console * Fix asset file locking tests * Add testcommand timeout + improve dotnet-new tests * WiP * Welcome, JoSequ! * Fix failing tests * Clean out diagnostics writelines * self-PR1
This commit is contained in:
parent
2b7e9b6524
commit
2fbafe6f3f
21 changed files with 353 additions and 753 deletions
|
@ -48,10 +48,14 @@
|
|||
</ProjectsToTest>
|
||||
</ItemGroup>
|
||||
|
||||
<Message Text="Starting test execution" Importance="High" />
|
||||
|
||||
<MSBuild
|
||||
BuildInParallel="True"
|
||||
Projects="@(ProjectsToTest)">
|
||||
</MSBuild>
|
||||
|
||||
<Message Text="Finished test execution" Importance="High" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PrepareTests"
|
||||
|
@ -232,18 +236,9 @@
|
|||
|
||||
<Target Name="RestoreTestAssetPackageProjects"
|
||||
DependsOnTargets="PrepareTests;
|
||||
SetupRestoreTestAssetPackageProjectsInputs;"
|
||||
Inputs="@(RestoreTestAssetPackageProjectsInputs)"
|
||||
Outputs="@(RestoreTestAssetPackageProjectsInputs->'%(RelativeDir)/obj/project.assets.json');@(RestoreTestAssetPackageProjectsInputs->'%(RelativeDir)/obj/%(Filename).csproj.nuget.g.props');@(RestoreTestAssetPackageProjectsInputs->'%(RelativeDir)/obj/%(Filename).csproj.nuget.g.targets')">
|
||||
SetupTestPackageProjectData;">
|
||||
|
||||
<DotNetRestore ToolPath="$(Stage0Directory)"
|
||||
ProjectPath=""%(RestoreTestAssetPackageProjectsInputs.FullPath)"" />
|
||||
<DotNetRestore ToolPath="$(Stage2Directory)"
|
||||
WorkingDirectory="%(TestPackageProject.FullPath)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="SetupRestoreTestAssetPackageProjectsInputs"
|
||||
DependsOnTargets="Init;">
|
||||
<ItemGroup>
|
||||
<RestoreTestAssetPackageProjectsInputs Include="$(RepoRoot)/TestAssets/TestPackages/**/*.csproj" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -37,15 +37,8 @@
|
|||
-->
|
||||
<PreTestProjectsToExclude Include="test$(PathSeparator)binding-redirects.Tests$(PathSeparator)binding-redirects.Tests.csproj;" />
|
||||
|
||||
<PreTestProjectsToExclude Condition=" 'https://github.com/dotnet/cli/issues/3864' != 'fixed' "
|
||||
Include="test$(PathSeparator)TestingAbstractions$(PathSeparator)Microsoft.Extensions.Testing.Abstractions.Tests$(PathSeparator)Microsoft.Extensions.Testing.Abstractions.Tests.csproj;
|
||||
test$(PathSeparator)TestingAbstractions$(PathSeparator)Microsoft.Extensions.Testing.Abstractions.UnitTests$(PathSeparator)Microsoft.Extensions.Testing.Abstractions.UnitTests.csproj;" />
|
||||
|
||||
<PreTestProjectsToExclude Condition=" 'https://github.com/dotnet/cli/issues/3216' != 'fixed' "
|
||||
Include="test$(PathSeparator)Kestrel.Tests$(PathSeparator)Kestrel.Tests.csproj" />
|
||||
|
||||
<PreTestProjectsToExclude Condition=" 'https://github.com/dotnet/cli/issues/3865' != 'fixed' "
|
||||
Include="test$(PathSeparator)ScriptExecutorTests$(PathSeparator)ScriptExecutorTests.csproj" />
|
||||
|
||||
<PreTestProjectsToExclude Condition=" 'Non-test projects in test directory' != 'consider moving elsewhere' "
|
||||
Include="test$(PathSeparator)ArgumentsReflector$(PathSeparator)ArgumentsReflector.csproj;
|
||||
|
|
|
@ -73,6 +73,10 @@ if (!(Test-Path $env:DOTNET_INSTALL_DIR))
|
|||
# Disable first run since we want to control all package sources
|
||||
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
|
||||
|
||||
# Enable vs test console logging
|
||||
$env:VSTEST_BUILD_TRACE=1
|
||||
$env:VSTEST_TRACE_BUILD=1
|
||||
|
||||
# set the base tools directory
|
||||
$toolsLocalPath = Join-Path $PSScriptRoot "build_tools"
|
||||
$bootStrapperPath = Join-Path $toolsLocalPath "bootstrap.ps1"
|
||||
|
@ -118,6 +122,6 @@ if ($NoBuild)
|
|||
}
|
||||
else
|
||||
{
|
||||
dotnet msbuild build.proj /m /p:Architecture=$Architecture $ExtraParameters
|
||||
dotnet msbuild build.proj /m /v:diag /p:Architecture=$Architecture $ExtraParameters
|
||||
if($LASTEXITCODE -ne 0) { throw "Failed to build" }
|
||||
}
|
||||
|
|
|
@ -139,6 +139,10 @@ done < "$REPOROOT/branchinfo.txt"
|
|||
# During xplat bootstrapping, disable HTTP parallelism to avoid fatal restore timeouts.
|
||||
export __INIT_TOOLS_RESTORE_ARGS="$__INIT_TOOLS_RESTORE_ARGS --disable-parallel"
|
||||
|
||||
# Enable verbose VS Test Console logging
|
||||
export VSTEST_BUILD_TRACE=1
|
||||
export VSTEST_TRACE_BUILD=1
|
||||
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
|
||||
toolsLocalPath="$REPOROOT/build_tools"
|
||||
bootStrapperPath="$toolsLocalPath/bootstrap.sh"
|
||||
|
@ -183,7 +187,7 @@ export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
|
|||
echo "${args[@]}"
|
||||
|
||||
if [ $BUILD -eq 1 ]; then
|
||||
dotnet msbuild build.proj /m /p:Architecture=$ARCHITECTURE "${args[@]}"
|
||||
dotnet msbuild build.proj /m /v:diag /p:Architecture=$ARCHITECTURE "${args[@]}"
|
||||
else
|
||||
echo "Not building due to --nobuild"
|
||||
echo "Command that would be run is: 'dotnet msbuild build.proj /m /p:Architecture=$ARCHITECTURE ${args[@]}'"
|
||||
|
|
|
@ -179,7 +179,9 @@ namespace Microsoft.DotNet.Cli.Utils
|
|||
|
||||
try
|
||||
{
|
||||
lockFile = new LockFileFormat().Read(lockFilePath);
|
||||
lockFile = new LockFileFormat()
|
||||
.ReadWithLock(lockFilePath)
|
||||
.Result;
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
|
|
|
@ -21,17 +21,23 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
|
||||
public FileInfoNuGetLock(FileInfo fileInfo)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
_task = ConcurrencyUtilities.ExecuteWithFileLockedAsync<int>(
|
||||
_task = Task.Run(async () => await ConcurrencyUtilities.ExecuteWithFileLockedAsync<int>(
|
||||
fileInfo.FullName,
|
||||
lockedToken =>
|
||||
cancellationToken =>
|
||||
{
|
||||
Task.Delay(60000, _cancellationTokenSource.Token).Wait();
|
||||
taskCompletionSource.SetResult("Lock is taken so test can continue");
|
||||
|
||||
Task.Delay(60000, cancellationToken).Wait();
|
||||
|
||||
return Task.FromResult(0);
|
||||
},
|
||||
_cancellationTokenSource.Token);
|
||||
_cancellationTokenSource.Token));
|
||||
|
||||
taskCompletionSource.Task.Wait();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -8,91 +8,34 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Test.Utilities
|
||||
{
|
||||
public class TestCommand
|
||||
{
|
||||
protected string _command;
|
||||
|
||||
private string _baseDirectory;
|
||||
|
||||
public string WorkingDirectory { get; set; }
|
||||
private List<string> _cliGeneratedEnvironmentVariables = new List<string> { "MSBuildSDKsPath" };
|
||||
|
||||
public Process CurrentProcess { get; set; }
|
||||
protected string _command;
|
||||
|
||||
public Process CurrentProcess { get; private set; }
|
||||
|
||||
public Dictionary<string, string> Environment { get; } = new Dictionary<string, string>();
|
||||
|
||||
private List<Action<string>> _writeLines = new List<Action<string>>();
|
||||
public event DataReceivedEventHandler ErrorDataReceived;
|
||||
|
||||
private List<string> _cliGeneratedEnvironmentVariables = new List<string> { "MSBuildSDKsPath" };
|
||||
public event DataReceivedEventHandler OutputDataReceived;
|
||||
|
||||
public string WorkingDirectory { get; set; }
|
||||
|
||||
public TestCommand(string command)
|
||||
{
|
||||
_command = command;
|
||||
#if NET451
|
||||
_baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||
#else
|
||||
_baseDirectory = AppContext.BaseDirectory;
|
||||
#endif
|
||||
}
|
||||
|
||||
public virtual CommandResult Execute(string args = "")
|
||||
{
|
||||
var commandPath = _command;
|
||||
ResolveCommand(ref commandPath, ref args);
|
||||
|
||||
Console.WriteLine($"Executing - {commandPath} {args} - {WorkingDirectoryInfo()}");
|
||||
|
||||
var stdOut = new StreamForwarder();
|
||||
var stdErr = new StreamForwarder();
|
||||
|
||||
AddWriteLine(Reporter.Output.WriteLine);
|
||||
|
||||
stdOut.ForwardTo(writeLine: WriteLine);
|
||||
stdErr.ForwardTo(writeLine: WriteLine);
|
||||
|
||||
return RunProcess(commandPath, args, stdOut, stdErr);
|
||||
}
|
||||
|
||||
public virtual Task<CommandResult> ExecuteAsync(string args = "")
|
||||
{
|
||||
var commandPath = _command;
|
||||
ResolveCommand(ref commandPath, ref args);
|
||||
|
||||
Console.WriteLine($"Executing - {commandPath} {args} - {WorkingDirectoryInfo()}");
|
||||
|
||||
var stdOut = new StreamForwarder();
|
||||
var stdErr = new StreamForwarder();
|
||||
|
||||
AddWriteLine(Reporter.Output.WriteLine);
|
||||
|
||||
stdOut.ForwardTo(writeLine: WriteLine);
|
||||
stdErr.ForwardTo(writeLine: WriteLine);
|
||||
|
||||
return RunProcessAsync(commandPath, args, stdOut, stdErr);
|
||||
}
|
||||
|
||||
public virtual CommandResult ExecuteWithCapturedOutput(string args = "")
|
||||
{
|
||||
var command = _command;
|
||||
ResolveCommand(ref command, ref args);
|
||||
var commandPath = Env.GetCommandPath(command, ".exe", ".cmd", "") ??
|
||||
Env.GetCommandPathFromRootPath(_baseDirectory, command, ".exe", ".cmd", "");
|
||||
|
||||
Console.WriteLine($"Executing (Captured Output) - {commandPath} {args} - {WorkingDirectoryInfo()}");
|
||||
|
||||
var stdOut = new StreamForwarder();
|
||||
var stdErr = new StreamForwarder();
|
||||
|
||||
stdOut.ForwardTo(writeLine: WriteLine);
|
||||
stdErr.ForwardTo(writeLine: WriteLine);
|
||||
|
||||
stdOut.Capture();
|
||||
stdErr.Capture();
|
||||
|
||||
return RunProcess(commandPath, args, stdOut, stdErr);
|
||||
_baseDirectory = GetBaseDirectory();
|
||||
}
|
||||
|
||||
public void KillTree()
|
||||
|
@ -105,176 +48,88 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
CurrentProcess.KillTree();
|
||||
}
|
||||
|
||||
public void AddWriteLine(Action<string> writeLine)
|
||||
public virtual CommandResult Execute(string args = "")
|
||||
{
|
||||
_writeLines.Add(writeLine);
|
||||
return Task.Run(async () => await ExecuteAsync(args)).Result;
|
||||
}
|
||||
|
||||
private void ResolveCommand(ref string executable, ref string args)
|
||||
public async virtual Task<CommandResult> ExecuteAsync(string args = "")
|
||||
{
|
||||
if (executable.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var newArgs = ArgumentEscaper.EscapeSingleArg(executable);
|
||||
if (!string.IsNullOrEmpty(args))
|
||||
{
|
||||
newArgs += " " + args;
|
||||
}
|
||||
args = newArgs;
|
||||
executable = "dotnet";
|
||||
}
|
||||
var resolvedCommand = _command;
|
||||
|
||||
if (!Path.IsPathRooted(executable))
|
||||
{
|
||||
executable = Env.GetCommandPath(executable) ??
|
||||
Env.GetCommandPathFromRootPath(_baseDirectory, executable);
|
||||
}
|
||||
ResolveCommand(ref resolvedCommand, ref args);
|
||||
|
||||
Console.WriteLine($"Executing - {resolvedCommand} {args} - {WorkingDirectoryInfo()}");
|
||||
|
||||
return await ExecuteAsyncInternal(resolvedCommand, args);
|
||||
}
|
||||
|
||||
private CommandResult RunProcess(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
|
||||
public virtual CommandResult ExecuteWithCapturedOutput(string args = "")
|
||||
{
|
||||
Task taskOut = null;
|
||||
var resolvedCommand = _command;
|
||||
|
||||
Task taskErr = null;
|
||||
|
||||
CurrentProcess = CreateProcess(executable, args);
|
||||
ResolveCommand(ref resolvedCommand, ref args);
|
||||
|
||||
CurrentProcess.Start();
|
||||
var commandPath = Env.GetCommandPath(resolvedCommand, ".exe", ".cmd", "") ??
|
||||
Env.GetCommandPathFromRootPath(_baseDirectory, resolvedCommand, ".exe", ".cmd", "");
|
||||
|
||||
try
|
||||
Console.WriteLine($"Executing (Captured Output) - {commandPath} {args} - {WorkingDirectoryInfo()}");
|
||||
|
||||
return Task.Run(async () => await ExecuteAsyncInternal(resolvedCommand, args)).Result;
|
||||
}
|
||||
|
||||
|
||||
private async Task<CommandResult> ExecuteAsyncInternal(string executable, string args)
|
||||
{
|
||||
var stdOut = new List<String>();
|
||||
|
||||
var stdErr = new List<String>();
|
||||
|
||||
CurrentProcess = CreateProcess(executable, args);
|
||||
|
||||
CurrentProcess.ErrorDataReceived += (s, e) =>
|
||||
{
|
||||
taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
||||
}
|
||||
catch (System.InvalidOperationException e)
|
||||
{
|
||||
if (!e.Message.Equals("The collection has been marked as complete with regards to additions."))
|
||||
stdErr.Add(e.Data);
|
||||
|
||||
var handler = ErrorDataReceived;
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
throw;
|
||||
handler(s, e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
CurrentProcess.OutputDataReceived += (s, e) =>
|
||||
{
|
||||
taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
||||
}
|
||||
catch (System.InvalidOperationException e)
|
||||
{
|
||||
if (!e.Message.Equals("The collection has been marked as complete with regards to additions."))
|
||||
stdOut.Add(e.Data);
|
||||
|
||||
var handler = OutputDataReceived;
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
throw;
|
||||
handler(s, e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var completionTask = CurrentProcess.StartAndWaitForExitAsync();
|
||||
|
||||
CurrentProcess.BeginOutputReadLine();
|
||||
|
||||
CurrentProcess.BeginErrorReadLine();
|
||||
|
||||
await completionTask;
|
||||
|
||||
CurrentProcess.WaitForExit();
|
||||
|
||||
var tasksToAwait = new List<Task>();
|
||||
RemoveNullTerminator(stdOut);
|
||||
|
||||
if (taskOut != null)
|
||||
{
|
||||
tasksToAwait.Add(taskOut);
|
||||
}
|
||||
RemoveNullTerminator(stdErr);
|
||||
|
||||
if (taskErr != null)
|
||||
{
|
||||
tasksToAwait.Add(taskErr);
|
||||
}
|
||||
|
||||
if (tasksToAwait.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasksToAwait.ToArray());
|
||||
}
|
||||
catch (System.ObjectDisposedException e)
|
||||
{
|
||||
taskErr = null;
|
||||
|
||||
taskOut = null;
|
||||
}
|
||||
}
|
||||
|
||||
var result = new CommandResult(
|
||||
return new CommandResult(
|
||||
CurrentProcess.StartInfo,
|
||||
CurrentProcess.ExitCode,
|
||||
stdOut?.CapturedOutput ?? CurrentProcess.StandardOutput.ReadToEnd(),
|
||||
stdErr?.CapturedOutput ?? CurrentProcess.StandardError.ReadToEnd());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Task<CommandResult> RunProcessAsync(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr)
|
||||
{
|
||||
Task taskOut = null;
|
||||
|
||||
Task taskErr = null;
|
||||
|
||||
CurrentProcess = CreateProcess(executable, args);
|
||||
|
||||
CurrentProcess.Start();
|
||||
|
||||
try
|
||||
{
|
||||
taskOut = stdOut.BeginRead(CurrentProcess.StandardOutput);
|
||||
}
|
||||
catch (System.InvalidOperationException e)
|
||||
{
|
||||
if (!e.Message.Equals("The collection has been marked as complete with regards to additions."))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
taskErr = stdErr.BeginRead(CurrentProcess.StandardError);
|
||||
}
|
||||
catch (System.InvalidOperationException e)
|
||||
{
|
||||
if (!e.Message.Equals("The collection has been marked as complete with regards to additions."))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
var tcs = new TaskCompletionSource<CommandResult>();
|
||||
|
||||
CurrentProcess.Exited += (sender, arg) =>
|
||||
{
|
||||
var tasksToAwait = new List<Task>();
|
||||
|
||||
if (taskOut != null)
|
||||
{
|
||||
tasksToAwait.Add(taskOut);
|
||||
}
|
||||
|
||||
if (taskErr != null)
|
||||
{
|
||||
tasksToAwait.Add(taskErr);
|
||||
}
|
||||
|
||||
if (tasksToAwait.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasksToAwait.ToArray());
|
||||
}
|
||||
catch (System.ObjectDisposedException e)
|
||||
{
|
||||
taskErr = null;
|
||||
|
||||
taskOut = null;
|
||||
}
|
||||
}
|
||||
|
||||
var result = new CommandResult(
|
||||
CurrentProcess.StartInfo,
|
||||
CurrentProcess.ExitCode,
|
||||
stdOut?.CapturedOutput ?? CurrentProcess.StandardOutput.ReadToEnd(),
|
||||
stdErr?.CapturedOutput ?? CurrentProcess.StandardError.ReadToEnd());
|
||||
|
||||
tcs.SetResult(result);
|
||||
};
|
||||
|
||||
return tcs.Task;
|
||||
String.Join(System.Environment.NewLine, stdOut),
|
||||
String.Join(System.Environment.NewLine, stdErr));
|
||||
}
|
||||
|
||||
private Process CreateProcess(string executable, string args)
|
||||
|
@ -289,21 +144,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
UseShellExecute = false
|
||||
};
|
||||
|
||||
RemoveCliGeneratedEnvironmentVariables(psi);
|
||||
RemoveCliGeneratedEnvironmentVariablesFrom(psi);
|
||||
|
||||
foreach (var item in Environment)
|
||||
{
|
||||
#if NET451
|
||||
psi.EnvironmentVariables[item.Key] = item.Value;
|
||||
#else
|
||||
psi.Environment[item.Key] = item.Value;
|
||||
#endif
|
||||
}
|
||||
AddEnvironmentVariablesTo(psi);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(WorkingDirectory))
|
||||
{
|
||||
psi.WorkingDirectory = WorkingDirectory;
|
||||
}
|
||||
AddWorkingDirectoryTo(psi);
|
||||
|
||||
var process = new Process
|
||||
{
|
||||
|
@ -315,14 +160,6 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
return process;
|
||||
}
|
||||
|
||||
private void WriteLine(string line)
|
||||
{
|
||||
foreach (var writeLine in _writeLines)
|
||||
{
|
||||
writeLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
private string WorkingDirectoryInfo()
|
||||
{
|
||||
if (WorkingDirectory == null)
|
||||
|
@ -333,7 +170,54 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
return $" in pwd {WorkingDirectory}";
|
||||
}
|
||||
|
||||
private void RemoveCliGeneratedEnvironmentVariables(ProcessStartInfo psi)
|
||||
private void RemoveNullTerminator(List<string> strings)
|
||||
{
|
||||
var count = strings.Count;
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (strings[count - 1] == null)
|
||||
{
|
||||
strings.RemoveAt(count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetBaseDirectory()
|
||||
{
|
||||
#if NET451
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
#else
|
||||
return AppContext.BaseDirectory;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void ResolveCommand(ref string executable, ref string args)
|
||||
{
|
||||
if (executable.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var newArgs = ArgumentEscaper.EscapeSingleArg(executable);
|
||||
|
||||
if (!string.IsNullOrEmpty(args))
|
||||
{
|
||||
newArgs += " " + args;
|
||||
}
|
||||
|
||||
args = newArgs;
|
||||
|
||||
executable = "dotnet";
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(executable))
|
||||
{
|
||||
executable = Env.GetCommandPath(executable) ??
|
||||
Env.GetCommandPathFromRootPath(_baseDirectory, executable);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveCliGeneratedEnvironmentVariablesFrom(ProcessStartInfo psi)
|
||||
{
|
||||
foreach (var name in _cliGeneratedEnvironmentVariables)
|
||||
{
|
||||
|
@ -344,5 +228,25 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void AddEnvironmentVariablesTo(ProcessStartInfo psi)
|
||||
{
|
||||
foreach (var item in Environment)
|
||||
{
|
||||
#if NET451
|
||||
psi.EnvironmentVariables[item.Key] = item.Value;
|
||||
#else
|
||||
psi.Environment[item.Key] = item.Value;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void AddWorkingDirectoryTo(ProcessStartInfo psi)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(WorkingDirectory))
|
||||
{
|
||||
psi.WorkingDirectory = WorkingDirectory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Test.Utilities
|
||||
{
|
||||
|
@ -110,5 +111,23 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
|
||||
return process.ExitCode;
|
||||
}
|
||||
|
||||
public static Task StartAndWaitForExitAsync(this Process subject)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<object>();
|
||||
|
||||
subject.EnableRaisingEvents = true;
|
||||
|
||||
subject.Exited += (s, a) =>
|
||||
{
|
||||
taskCompletionSource.SetResult(null);
|
||||
|
||||
subject.Dispose();
|
||||
};
|
||||
|
||||
subject.Start();
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
{
|
||||
public static class TestCommandExtensions
|
||||
{
|
||||
|
||||
public static TCommand WithWorkingDirectory<TCommand>(this TCommand subject, string workingDirectory) where TCommand : TestCommand
|
||||
{
|
||||
subject.WorkingDirectory = workingDirectory;
|
||||
|
@ -35,11 +34,27 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
|
|||
return subject;
|
||||
}
|
||||
|
||||
public static TCommand WithWriteLine<TCommand>(this TCommand subject, Action<string> writeLine) where TCommand : TestCommand
|
||||
public static TCommand WithOutputDataReceivedHandler<TCommand>(this TCommand subject, Action<string> writeLine) where TCommand : TestCommand
|
||||
{
|
||||
subject.AddWriteLine(writeLine);
|
||||
subject.OutputDataReceived += (s, e) => writeLine(e.Data);
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
public static TCommand WithErrorDataReceivedHandler<TCommand>(this TCommand subject, Action<string> writeLine) where TCommand : TestCommand
|
||||
{
|
||||
subject.ErrorDataReceived += (s, e) => writeLine(e.Data);
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
public static TCommand WithForwardingToConsole<TCommand>(this TCommand subject, Action<string> writeLine) where TCommand : TestCommand
|
||||
{
|
||||
subject.WithOutputDataReceivedHandler(s => Console.Out.WriteLine(s));
|
||||
|
||||
subject.WithErrorDataReceivedHandler(s => Console.Error.WriteLine(s));
|
||||
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using System.Runtime.InteropServices;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.Utils.ScriptExecutorTests
|
||||
{
|
||||
public class ScriptExecutorTests : TestBase
|
||||
{
|
||||
private static readonly string s_testProjectRoot = Path.Combine(AppContext.BaseDirectory, "TestAssets/TestProjects");
|
||||
|
||||
private TempDirectory _root;
|
||||
private string binTestProjectPath;
|
||||
private Project project;
|
||||
|
||||
public ScriptExecutorTests()
|
||||
{
|
||||
_root = Temp.CreateDirectory();
|
||||
|
||||
var sourceTestProjectPath = Path.Combine(s_testProjectRoot, "TestApp");
|
||||
binTestProjectPath = _root.CopyDirectory(sourceTestProjectPath).Path;
|
||||
project = ProjectContext.Create(binTestProjectPath, NuGetFramework.Parse("netcoreapp1.0")).ProjectFile;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_Project_Local_Script_is_Resolved()
|
||||
{
|
||||
CreateTestFile("some.script", binTestProjectPath);
|
||||
var scriptCommandLine = "some.script";
|
||||
|
||||
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||
|
||||
command.Should().NotBeNull();
|
||||
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_Nonexistent_Project_Local_Script_throws_CommandUnknownException()
|
||||
{
|
||||
var scriptCommandLine = "nonexistent.script";
|
||||
|
||||
Action action = () => ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||
action.ShouldThrow<CommandUnknownException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_Extension_sh_is_Inferred_over_cmd_in_Project_Local_Scripts_on_Unix()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var extensionList = new string[] { ".cmd", ".sh" };
|
||||
|
||||
var expectedExtension = ".sh";
|
||||
|
||||
foreach (var extension in extensionList)
|
||||
{
|
||||
CreateTestFile("uniquescriptname" + extension, binTestProjectPath);
|
||||
}
|
||||
|
||||
// Don't include extension
|
||||
var scriptCommandLine = "uniquescriptname";
|
||||
|
||||
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||
|
||||
command.Should().NotBeNull();
|
||||
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||
command.CommandArgs.Should().Contain(scriptCommandLine + expectedExtension);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_Extension_cmd_is_Inferred_over_sh_in_Project_Local_Scripts_on_Windows()
|
||||
{
|
||||
if (! RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var extensionList = new string[] { ".cmd", ".sh" };
|
||||
|
||||
var expectedExtension = ".cmd";
|
||||
|
||||
foreach (var extension in extensionList)
|
||||
{
|
||||
CreateTestFile("uniquescriptname" + extension, binTestProjectPath);
|
||||
}
|
||||
|
||||
// Don't include extension
|
||||
var scriptCommandLine = "uniquescriptname";
|
||||
|
||||
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||
|
||||
command.Should().NotBeNull();
|
||||
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||
command.CommandArgs.Should().Contain(scriptCommandLine + expectedExtension);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_Script_Exe_Files_Dont_Use_Cmd_or_Sh()
|
||||
{
|
||||
CreateTestFile("some.exe", binTestProjectPath);
|
||||
var scriptCommandLine = "some.exe";
|
||||
|
||||
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||
|
||||
command.Should().NotBeNull();
|
||||
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||
|
||||
Path.GetFileName(command.CommandName).Should().NotBe("cmd.exe");
|
||||
Path.GetFileName(command.CommandName).Should().NotBe("sh");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_Script_Cmd_Files_Use_CmdExe()
|
||||
{
|
||||
if (! RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CreateTestFile("some.cmd", binTestProjectPath);
|
||||
var scriptCommandLine = "some.cmd";
|
||||
|
||||
var command = ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||
|
||||
command.Should().NotBeNull();
|
||||
command.ResolutionStrategy.Should().Be(CommandResolutionStrategy.ProjectLocal);
|
||||
|
||||
Path.GetFileName(command.CommandName).Should().Be("cmd.exe");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_Script_Builtins_throws_CommandUnknownException()
|
||||
{
|
||||
var scriptCommandLine = "echo";
|
||||
|
||||
Action action = () => ScriptExecutor.CreateCommandForScript(project, scriptCommandLine, new Dictionary<string, string>());
|
||||
action.ShouldThrow<CommandUnknownException>();
|
||||
}
|
||||
|
||||
private void CreateTestFile(string filename, string directory)
|
||||
{
|
||||
string path = Path.Combine(directory, filename);
|
||||
File.WriteAllText(path, "echo hello");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.0</TargetFramework>
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||
<AssemblyName>ScriptExecutorTests</AssemblyName>
|
||||
<PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);dotnet5.4;portable-net451+win8</PackageTargetFallback>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="**\*.cs" />
|
||||
<EmbeddedResource Include="**\*.resx" />
|
||||
<EmbeddedResource Include="compiler\resources\**\*" />
|
||||
<Content Include="..\..\TestAssets\TestProjects\TestApp\**\*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.DotNet.Tools.Tests.Utilities\Microsoft.DotNet.Tools.Tests.Utilities.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.DotNet.TestFramework\Microsoft.DotNet.TestFramework.csproj">
|
||||
<FromP2P>true</FromP2P>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\src\Microsoft.DotNet.InternalAbstractions\Microsoft.DotNet.InternalAbstractions.csproj">
|
||||
<FromP2P>true</FromP2P>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
|
||||
<Reference Include="System.Runtime">
|
||||
<FromP2P>true</FromP2P>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Sdk">
|
||||
<Version>$(CLI_NETSDK_Version)</Version>
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk">
|
||||
<Version>15.0.0-preview-20161024-02</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit.runner.visualstudio">
|
||||
<Version>2.2.0-beta4-build1194</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.App">
|
||||
<Version>1.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit">
|
||||
<Version>2.2.0-beta4-build3444</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -717,7 +717,7 @@ namespace Microsoft.DotNet.Cli.Add.P2P.Tests
|
|||
.Execute($"{frameworkArg} \"{lib.CsProjPath}\"");
|
||||
cmd.Should().Fail();
|
||||
cmd.StdErr.Should().MatchRegex(ProjectNotCompatibleErrorMessageRegEx);
|
||||
cmd.StdErr.Should().MatchRegex(" - net45(\n|\r)");
|
||||
cmd.StdErr.Should().MatchRegex(" - net45");
|
||||
net45lib.CsProjContent().Should().BeEquivalentTo(csProjContent);
|
||||
}
|
||||
}
|
||||
|
|
71
test/dotnet-new.Tests/GivenThatIWantANewApp.cs
Normal file
71
test/dotnet-new.Tests/GivenThatIWantANewApp.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace Microsoft.DotNet.New.Tests
|
||||
{
|
||||
public class GivenThatIWantANewApp : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void When_dotnet_new_is_invoked_mupliple_times_it_should_fail()
|
||||
{
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute("new");
|
||||
|
||||
DateTime expectedState = Directory.GetLastWriteTime(rootPath);
|
||||
|
||||
var result = new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.ExecuteWithCapturedOutput("new");
|
||||
|
||||
DateTime actualState = Directory.GetLastWriteTime(rootPath);
|
||||
|
||||
Assert.Equal(expectedState, actualState);
|
||||
|
||||
result.Should().Fail()
|
||||
.And.HaveStdErr();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RestoreDoesNotUseAnyCliProducedPackagesOnItsTemplates()
|
||||
{
|
||||
var cSharpTemplates = new [] { "Console", "Lib", "Web", "Mstest", "XUnittest" };
|
||||
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||
var packagesDirectory = Path.Combine(rootPath, "packages");
|
||||
|
||||
foreach (var cSharpTemplate in cSharpTemplates)
|
||||
{
|
||||
var projectFolder = Path.Combine(rootPath, cSharpTemplate);
|
||||
Directory.CreateDirectory(projectFolder);
|
||||
CreateAndRestoreNewProject(cSharpTemplate, projectFolder, packagesDirectory);
|
||||
}
|
||||
|
||||
Directory.EnumerateFiles(packagesDirectory, $"*.nupkg", SearchOption.AllDirectories)
|
||||
.Should().NotContain(p => p.Contains("Microsoft.DotNet.Cli.Utils"));
|
||||
}
|
||||
|
||||
private void CreateAndRestoreNewProject(
|
||||
string projectType,
|
||||
string projectFolder,
|
||||
string packagesDirectory)
|
||||
{
|
||||
new TestCommand("dotnet") { WorkingDirectory = projectFolder }
|
||||
.Execute($"new --type {projectType}")
|
||||
.Should().Pass();
|
||||
|
||||
new RestoreCommand()
|
||||
.WithWorkingDirectory(projectFolder)
|
||||
.Execute($"--packages {packagesDirectory} /p:SkipInvalidConfigurations=true")
|
||||
.Should().Pass();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,22 +13,29 @@ using FluentAssertions;
|
|||
|
||||
namespace Microsoft.DotNet.New.Tests
|
||||
{
|
||||
public class GivenThatIWantANewFSAppWithSpecifiedType : TestBase
|
||||
public class GivenThatIWantANewAppWithSpecifiedType : TestBase
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Console", false)]
|
||||
[InlineData("Lib", false)]
|
||||
[InlineData("Web", true)]
|
||||
[InlineData("Mstest", false)]
|
||||
[InlineData("XUnittest", false)]
|
||||
public void When_dotnet_build_is_invoked_then_project_restores_and_builds_without_warnings_fs(
|
||||
[InlineData("C#", "Console", false)]
|
||||
[InlineData("C#", "Lib", false)]
|
||||
[InlineData("C#", "Web", true)]
|
||||
[InlineData("C#", "Mstest", false)]
|
||||
[InlineData("C#", "XUnittest", false)]
|
||||
[InlineData("F#", "Console", false)]
|
||||
[InlineData("F#", "Lib", false)]
|
||||
[InlineData("F#", "Web", true)]
|
||||
[InlineData("F#", "Mstest", false)]
|
||||
[InlineData("F#", "XUnittest", false)]
|
||||
public void TemplateRestoresAndBuildsWithoutWarnings(
|
||||
string language,
|
||||
string projectType,
|
||||
bool useNuGetConfigForAspNet)
|
||||
{
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory(callingMethod: "fs").Path;
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory(identifier: $"{language}_{projectType}").Path;
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute($"new --lang fsharp --type {projectType}")
|
||||
new TestCommand("dotnet")
|
||||
.WithWorkingDirectory(rootPath)
|
||||
.Execute($"new --type {projectType} --lang {language}")
|
||||
.Should().Pass();
|
||||
|
||||
if (useNuGetConfigForAspNet)
|
||||
|
@ -36,8 +43,9 @@ namespace Microsoft.DotNet.New.Tests
|
|||
File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(rootPath, "NuGet.Config"));
|
||||
}
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute($"restore /p:SkipInvalidConfigurations=true")
|
||||
new TestCommand("dotnet")
|
||||
.WithWorkingDirectory(rootPath)
|
||||
.Execute($"restore")
|
||||
.Should().Pass();
|
||||
|
||||
var buildResult = new TestCommand("dotnet")
|
|
@ -1,64 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace Microsoft.DotNet.New.Tests
|
||||
{
|
||||
public class GivenThatIWantANewCSApp : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void When_dotnet_build_is_invoked_Then_app_builds_without_warnings()
|
||||
{
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute("new");
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute("restore /p:SkipInvalidConfigurations=true");
|
||||
|
||||
var buildResult = new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.ExecuteWithCapturedOutput("build");
|
||||
|
||||
buildResult.Should().Pass()
|
||||
.And.NotHaveStdErr();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_dotnet_new_is_invoked_mupliple_times_it_should_fail()
|
||||
{
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute("new");
|
||||
|
||||
DateTime expectedState = Directory.GetLastWriteTime(rootPath);
|
||||
|
||||
var result = new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.ExecuteWithCapturedOutput("new");
|
||||
|
||||
DateTime actualState = Directory.GetLastWriteTime(rootPath);
|
||||
|
||||
Assert.Equal(expectedState, actualState);
|
||||
|
||||
result.Should().Fail()
|
||||
.And.HaveStdErr();
|
||||
}
|
||||
|
||||
internal static void AddProjectDependency(string projectFilePath, string dependencyId, string dependencyVersion)
|
||||
{
|
||||
var projectRootElement = ProjectRootElement.Open(projectFilePath);
|
||||
|
||||
projectRootElement.AddItem("PackageReference", dependencyId, new Dictionary<string, string>{{"Version", dependencyVersion}});
|
||||
|
||||
projectRootElement.Save();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace Microsoft.DotNet.New.Tests
|
||||
{
|
||||
public class GivenThatIWantANewCSAppWithSpecifiedType : TestBase
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Console", false)]
|
||||
[InlineData("Lib", false)]
|
||||
[InlineData("Web", true)]
|
||||
[InlineData("Mstest", false)]
|
||||
[InlineData("XUnittest", false)]
|
||||
public void ICanRestoreBuildAndPublishTheAppWithoutWarnings(
|
||||
string projectType,
|
||||
bool useNuGetConfigForAspNet)
|
||||
{
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory(callingMethod: "i").Path;
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute($"new --type {projectType}")
|
||||
.Should().Pass();
|
||||
|
||||
if (useNuGetConfigForAspNet)
|
||||
{
|
||||
File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(rootPath, "NuGet.Config"));
|
||||
}
|
||||
|
||||
new RestoreCommand()
|
||||
.WithWorkingDirectory(rootPath)
|
||||
.Execute("/p:SkipInvalidConfigurations=true")
|
||||
.Should().Pass();
|
||||
|
||||
new BuildCommand()
|
||||
.WithWorkingDirectory(rootPath)
|
||||
.ExecuteWithCapturedOutput()
|
||||
.Should().Pass()
|
||||
.And.NotHaveStdErr();
|
||||
|
||||
new PublishCommand()
|
||||
.WithWorkingDirectory(rootPath)
|
||||
.ExecuteWithCapturedOutput()
|
||||
.Should().Pass()
|
||||
.And.NotHaveStdErr();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RestoreDoesNotUseAnyCliProducedPackagesOnItsTemplates()
|
||||
{
|
||||
var cSharpTemplates = new [] { "Console", "Lib", "Web", "Mstest", "XUnittest" };
|
||||
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||
var packagesDirectory = Path.Combine(rootPath, "packages");
|
||||
|
||||
foreach (var cSharpTemplate in cSharpTemplates)
|
||||
{
|
||||
var projectFolder = Path.Combine(rootPath, cSharpTemplate);
|
||||
Directory.CreateDirectory(projectFolder);
|
||||
CreateAndRestoreNewProject(cSharpTemplate, projectFolder, packagesDirectory);
|
||||
}
|
||||
|
||||
Directory.EnumerateFiles(packagesDirectory, $"*.nupkg", SearchOption.AllDirectories)
|
||||
.Should().NotContain(p => p.Contains("Microsoft.DotNet.Cli.Utils"));
|
||||
}
|
||||
|
||||
private void CreateAndRestoreNewProject(
|
||||
string projectType,
|
||||
string projectFolder,
|
||||
string packagesDirectory)
|
||||
{
|
||||
new TestCommand("dotnet") { WorkingDirectory = projectFolder }
|
||||
.Execute($"new --type {projectType}")
|
||||
.Should().Pass();
|
||||
|
||||
new RestoreCommand()
|
||||
.WithWorkingDirectory(projectFolder)
|
||||
.Execute($"--packages {packagesDirectory} /p:SkipInvalidConfigurations=true")
|
||||
.Should().Pass();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace Microsoft.DotNet.New.Tests
|
||||
{
|
||||
public class GivenThatIWantANewFSApp : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void When_dotnet_build_is_invoked_Then_app_builds_without_warnings_fs()
|
||||
{
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute("new --lang f#");
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute("restore /p:SkipInvalidConfigurations=true");
|
||||
|
||||
var buildResult = new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.ExecuteWithCapturedOutput("build");
|
||||
|
||||
buildResult.Should().Pass()
|
||||
.And.NotHaveStdErr();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_dotnet_new_is_invoked_mupliple_times_it_should_fail_fs()
|
||||
{
|
||||
var rootPath = TestAssetsManager.CreateTestDirectory().Path;
|
||||
|
||||
new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.Execute("new --lang f#");
|
||||
|
||||
DateTime expectedState = Directory.GetLastWriteTime(rootPath);
|
||||
|
||||
var result = new TestCommand("dotnet") { WorkingDirectory = rootPath }
|
||||
.ExecuteWithCapturedOutput("new --lang f#");
|
||||
|
||||
DateTime actualState = Directory.GetLastWriteTime(rootPath);
|
||||
|
||||
Assert.Equal(expectedState, actualState);
|
||||
|
||||
result.Should().Fail()
|
||||
.And.HaveStdErr();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,39 +16,28 @@ namespace Microsoft.DotNet.Cli.VSTest.Tests
|
|||
[Fact]
|
||||
public void TestsFromAGivenContainerShouldRunWithExpectedOutput()
|
||||
{
|
||||
// Copy VSTestDotNetCore project in output directory of project dotnet-vstest.Tests
|
||||
string testAppName = "VSTestDotNetCore";
|
||||
TestInstance testInstance = TestAssetsManager.CreateTestInstance(testAppName);
|
||||
var testAppName = "VSTestDotNetCore";
|
||||
var testRoot = TestAssets.Get(testAppName)
|
||||
.CreateInstance()
|
||||
.WithRestoreFiles()
|
||||
.WithBuildFiles()
|
||||
.Root;
|
||||
|
||||
string testProjectDirectory = testInstance.TestRoot;
|
||||
var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? "Debug";
|
||||
|
||||
// Restore project VSTestDotNetCore
|
||||
new RestoreCommand()
|
||||
.WithWorkingDirectory(testProjectDirectory)
|
||||
.Execute()
|
||||
.Should()
|
||||
.Pass();
|
||||
var outputDll = testRoot
|
||||
.GetDirectory("bin", configuration, "netcoreapp1.0")
|
||||
.GetFile($"{testAppName}.dll");
|
||||
|
||||
// Build project VSTestDotNetCore
|
||||
new BuildCommand()
|
||||
.WithWorkingDirectory(testProjectDirectory)
|
||||
.Execute()
|
||||
.Should()
|
||||
.Pass();
|
||||
|
||||
// Prepare args to send vstest
|
||||
string configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? "Debug";
|
||||
string testAdapterPath = Path.Combine(testProjectDirectory, "bin", configuration, "netcoreapp1.0");
|
||||
string outputDll = Path.Combine(testAdapterPath, $"{testAppName}.dll");
|
||||
string argsForVstest = string.Concat("\"", outputDll, "\"");
|
||||
var argsForVstest = $"\"{outputDll.FullName}\"";
|
||||
|
||||
// Call vstest
|
||||
CommandResult result = new VSTestCommand().ExecuteWithCapturedOutput(argsForVstest);
|
||||
|
||||
// Verify
|
||||
result.StdOut.Should().Contain("Total tests: 2. Passed: 1. Failed: 1. Skipped: 0.");
|
||||
result.StdOut.Should().Contain("Passed TestNamespace.VSTestTests.VSTestPassTest");
|
||||
result.StdOut.Should().Contain("Failed TestNamespace.VSTestTests.VSTestFailTest");
|
||||
new VSTestCommand()
|
||||
.ExecuteWithCapturedOutput(argsForVstest)
|
||||
.StdOut
|
||||
.Should().Contain("Total tests: 2. Passed: 1. Failed: 1. Skipped: 0.")
|
||||
.And.Contain("Passed TestNamespace.VSTestTests.VSTestPassTest")
|
||||
.And.Contain("Failed TestNamespace.VSTestTests.VSTestFailTest");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void When_invoked_then_dotnet_writes_optimization_data_to_the_profile_root()
|
||||
public void WhenInvokedThenDotnetWritesOptimizationDataToTheProfileRoot()
|
||||
{
|
||||
var testDirectory = TestAssetsManager.CreateTestDirectory();
|
||||
var testStartTime = GetTruncatedDateTime();
|
||||
|
@ -43,7 +43,7 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void When_invoked_with_MulticoreJit_disabled_then_dotnet_does_not_writes_optimization_data_to_the_profile_root()
|
||||
public void WhenInvokedWithMulticoreJitDisabledThenDotnetDoesNotWriteOptimizationDataToTheProfileRoot()
|
||||
{
|
||||
var testDirectory = TestAssetsManager.CreateTestDirectory();
|
||||
var testStartTime = GetTruncatedDateTime();
|
||||
|
@ -60,7 +60,7 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void When_the_profile_root_is_undefined_then_dotnet_does_not_crash()
|
||||
public void WhenTheProfileRootIsUndefinedThenDotnetDoesNotCrash()
|
||||
{
|
||||
var testDirectory = TestAssetsManager.CreateTestDirectory();
|
||||
var testStartTime = GetTruncatedDateTime();
|
||||
|
@ -74,7 +74,7 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void When_cli_repo_builds_then_dotnet_writes_optimization_data_to_the_default_profile_root()
|
||||
public void WhenCliRepoBuildsThenDotnetWritesOptimizationDataToTheDefaultProfileRoot()
|
||||
{
|
||||
var optimizationProfileFilePath = GetOptimizationProfileFilePath();
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Using_dotnet_for_the_first_time_succeeds()
|
||||
public void UsingDotnetForTheFirstTimeSucceeds()
|
||||
{
|
||||
_firstDotnetVerbUseCommandResult
|
||||
.Should()
|
||||
|
@ -45,7 +45,7 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Using_dotnet_for_the_first_time_with_non_verbs_doesnt_print_eula()
|
||||
public void UsingDotnetForTheFirstTimeWithNonVerbsDoesNotPrintEula()
|
||||
{
|
||||
const string firstTimeNonVerbUseMessage = @".NET Command Line Tools";
|
||||
|
||||
|
@ -55,28 +55,30 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void It_shows_the_appropriate_message_to_the_user()
|
||||
public void ItShowsTheAppropriateMessageToTheUser()
|
||||
{
|
||||
string firstTimeUseWelcomeMessage = NormalizeLineEndings(@"Welcome to .NET Core!
|
||||
---------------------
|
||||
Learn more about .NET Core @ https://aka.ms/dotnet-docs. Use dotnet --help to see available commands or go to https://aka.ms/dotnet-cli-docs.
|
||||
|
||||
Telemetry
|
||||
--------------
|
||||
The .NET Core tools collect usage data in order to improve your experience. The data is anonymous and does not include commandline arguments. The data is collected by Microsoft and shared with the community.
|
||||
You can opt out of telemetry by setting a DOTNET_CLI_TELEMETRY_OPTOUT environment variable to 1 using your favorite shell.
|
||||
You can read more about .NET Core tools telemetry @ https://aka.ms/dotnet-cli-telemetry.
|
||||
|
||||
Configuring...
|
||||
-------------------
|
||||
A command is running to initially populate your local package cache, to improve restore speed and enable offline access. This command will take up to a minute to complete and will only happen once.");
|
||||
|
||||
// normalizing line endings as git is occasionally replacing line endings in this file causing this test to fail
|
||||
NormalizeLineEndings(_firstDotnetVerbUseCommandResult.StdOut)
|
||||
.Should().StartWith(firstTimeUseWelcomeMessage)
|
||||
.Should().Contain(firstTimeUseWelcomeMessage)
|
||||
.And.NotContain("Restore completed in");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void It_restores_the_nuget_packages_to_the_nuget_cache_folder()
|
||||
public void ItRestoresTheNuGetPackagesToTheNuGetCacheFolder()
|
||||
{
|
||||
_nugetCacheFolder
|
||||
.Should()
|
||||
|
@ -84,7 +86,7 @@ A command is running to initially populate your local package cache, to improve
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void It_creates_a_sentinel_file_under_the_nuget_cache_folder()
|
||||
public void ItCreatesASentinelFileUnderTheNuGetCacheFolder()
|
||||
{
|
||||
_nugetCacheFolder
|
||||
.Should()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using FluentAssertions;
|
||||
|
@ -72,7 +73,7 @@ namespace Microsoft.DotNet.Tests
|
|||
new PortableCommand()
|
||||
.WithWorkingDirectory(testInstance.Root)
|
||||
.ExecuteWithCapturedOutput()
|
||||
.Should().HaveStdOutContaining("Hello Portable World!" + Environment.NewLine)
|
||||
.Should().HaveStdOutContaining("Hello Portable World!")
|
||||
.And.NotHaveStdErr()
|
||||
.And.Pass();
|
||||
}
|
||||
|
@ -111,14 +112,12 @@ namespace Microsoft.DotNet.Tests
|
|||
new BuildCommand()
|
||||
.WithProjectDirectory(testInstance.Root)
|
||||
.WithConfiguration("Debug")
|
||||
.WithWriteLine(_output.WriteLine)
|
||||
.Execute()
|
||||
.Should().Pass();
|
||||
|
||||
new DependencyToolInvokerCommand()
|
||||
.WithWorkingDirectory(testInstance.Root)
|
||||
.WithEnvironmentVariable(CommandContext.Variables.Verbose, "true")
|
||||
.WithWriteLine(_output.WriteLine)
|
||||
.ExecuteWithCapturedOutput($"tool-with-output-name", framework, "")
|
||||
.Should().HaveStdOutContaining("Tool with output name!")
|
||||
.And.NotHaveStdErr()
|
||||
|
@ -222,14 +221,18 @@ namespace Microsoft.DotNet.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void When_assets_file_is_in_use_Then_CLI_retries_launching_the_command_for_at_least_one_second()
|
||||
public void WhenToolAssetsFileIsInUseThenCLIRetriesLaunchingTheCommandForAtLeastOneSecond()
|
||||
{
|
||||
var testInstance = TestAssets.Get("AppWithToolDependency")
|
||||
.CreateInstance()
|
||||
.WithSourceFiles()
|
||||
.WithRestoreFiles();
|
||||
|
||||
var assetsFile = testInstance.Root.GetDirectory("obj").GetFile("project.assets.json");
|
||||
var assetsFile = new DirectoryInfo(new RepoDirectoriesProvider().NugetPackages)
|
||||
.GetDirectory(".tools", "dotnet-portable", "1.0.0", "netcoreapp1.0")
|
||||
.GetFile("project.assets.json");
|
||||
|
||||
var stopWatch = Stopwatch.StartNew();
|
||||
|
||||
using (assetsFile.Lock()
|
||||
.DisposeAfter(TimeSpan.FromMilliseconds(1000)))
|
||||
|
@ -237,21 +240,29 @@ namespace Microsoft.DotNet.Tests
|
|||
new PortableCommand()
|
||||
.WithWorkingDirectory(testInstance.Root)
|
||||
.ExecuteWithCapturedOutput()
|
||||
.Should().HaveStdOutContaining("Hello Portable World!" + Environment.NewLine)
|
||||
.Should().HaveStdOutContaining("Hello Portable World!")
|
||||
.And.NotHaveStdErr()
|
||||
.And.Pass();
|
||||
}
|
||||
|
||||
stopWatch.Stop();
|
||||
|
||||
stopWatch.ElapsedMilliseconds.Should().BeGreaterThan(1000, "Because dotnet should respect the NuGet lock");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void When_assets_file_is_locked_by_NuGet_Then_CLI_retries_launching_the_command_for_at_least_one_second()
|
||||
public void WhenToolAssetsFileIsLockedByNuGetThenCLIRetriesLaunchingTheCommandForAtLeastOneSecond()
|
||||
{
|
||||
var testInstance = TestAssets.Get("AppWithToolDependency")
|
||||
.CreateInstance()
|
||||
.WithSourceFiles()
|
||||
.WithRestoreFiles();
|
||||
|
||||
var assetsFile = testInstance.Root.GetDirectory("obj").GetFile("project.assets.json");
|
||||
var assetsFile = new DirectoryInfo(new RepoDirectoriesProvider().NugetPackages)
|
||||
.GetDirectory(".tools", "dotnet-portable", "1.0.0", "netcoreapp1.0")
|
||||
.GetFile("project.assets.json");
|
||||
|
||||
var stopWatch = Stopwatch.StartNew();
|
||||
|
||||
using (assetsFile.NuGetLock()
|
||||
.DisposeAfter(TimeSpan.FromMilliseconds(1000)))
|
||||
|
@ -259,10 +270,14 @@ namespace Microsoft.DotNet.Tests
|
|||
new PortableCommand()
|
||||
.WithWorkingDirectory(testInstance.Root)
|
||||
.ExecuteWithCapturedOutput()
|
||||
.Should().HaveStdOutContaining("Hello Portable World!" + Environment.NewLine)
|
||||
.Should().HaveStdOutContaining("Hello Portable World!")
|
||||
.And.NotHaveStdErr()
|
||||
.And.Pass();
|
||||
}
|
||||
|
||||
stopWatch.Stop();
|
||||
|
||||
stopWatch.ElapsedMilliseconds.Should().BeGreaterThan(1000, "Because dotnet should respect the NuGet lock");
|
||||
}
|
||||
|
||||
class HelloCommand : TestCommand
|
||||
|
|
Loading…
Reference in a new issue