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:
Piotr Puszkiewicz 2016-12-13 14:15:35 -08:00 committed by GitHub
parent 2b7e9b6524
commit 2fbafe6f3f
21 changed files with 353 additions and 753 deletions

View file

@ -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="&quot;%(RestoreTestAssetPackageProjectsInputs.FullPath)&quot;" />
<DotNetRestore ToolPath="$(Stage2Directory)"
WorkingDirectory="%(TestPackageProject.FullPath)" />
</Target>
<Target Name="SetupRestoreTestAssetPackageProjectsInputs"
DependsOnTargets="Init;">
<ItemGroup>
<RestoreTestAssetPackageProjectsInputs Include="$(RepoRoot)/TestAssets/TestPackages/**/*.csproj" />
</ItemGroup>
</Target>
</Project>
</Project>

View file

@ -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;

View file

@ -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" }
}

View file

@ -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[@]}'"

View file

@ -179,7 +179,9 @@ namespace Microsoft.DotNet.Cli.Utils
try
{
lockFile = new LockFileFormat().Read(lockFilePath);
lockFile = new LockFileFormat()
.ReadWithLock(lockFilePath)
.Result;
}
catch (FileFormatException ex)
{

View file

@ -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()

View file

@ -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;
}
}
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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");
}
}
}

View file

@ -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>

View file

@ -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);
}
}

View 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();
}
}
}

View file

@ -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")

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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");
}
}
}

View file

@ -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();

View file

@ -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()

View file

@ -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