Merge remote-tracking branch 'dotnet/release/2.1.3xx' into merges/release/2.1.3xx-to-release/2.1.4xx

This commit is contained in:
Tanner Gooding 2018-05-07 08:20:23 -07:00
commit 6d6bf64f28
308 changed files with 3304 additions and 1627 deletions

View file

@ -0,0 +1,222 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using FluentAssertions;
using Microsoft.DotNet.TestFramework;
using Microsoft.DotNet.Tools.Test.Utilities;
using NuGet.ProjectModel;
using NuGet.Versioning;
using Xunit;
namespace EndToEnd
{
public class GivenAspNetAppsResolveImplicitVersions : TestBase
{
private const string AspNetTestProject = "TestWebAppSimple";
[Fact]
public void PortablePublishWithLatestTFMUsesBundledAspNetCoreAppVersion()
{
var _testInstance = TestAssets.Get(AspNetTestProject)
.CreateInstance(identifier: LatestSupportedAspNetCoreAppVersion)
.WithSourceFiles();
string projectDirectory = _testInstance.Root.FullName;
string projectPath = Path.Combine(projectDirectory, $"{AspNetTestProject}.csproj");
var project = XDocument.Load(projectPath);
var ns = project.Root.Name.Namespace;
// Update TargetFramework to the right version of .NET Core
project.Root.Element(ns + "PropertyGroup")
.Element(ns + "TargetFramework")
.Value = "netcoreapp" + LatestSupportedAspNetCoreAppVersion;
project.Save(projectPath);
// Get the implicit version
new RestoreCommand()
.WithWorkingDirectory(projectDirectory)
.Execute()
.Should().Pass();
var assetsFilePath = Path.Combine(projectDirectory, "obj", "project.assets.json");
var assetsFile = new LockFileFormat().Read(assetsFilePath);
var restoredVersion = GetAspNetCoreAppVersion(assetsFile, portable: true);
restoredVersion.Should().NotBeNull();
var bundledVersionPath = Path.Combine(projectDirectory, ".BundledAspNetCoreVersion");
var bundledVersion = File.ReadAllText(bundledVersionPath).Trim();
restoredVersion.ToNormalizedString().Should().BeEquivalentTo(bundledVersion,
"The bundled aspnetcore versions set in Microsoft.NETCoreSdk.BundledVersions.props should be idenitical to the versions set in DependencyVersions.props." +
"Please update MSBuildExtensions.targets in this repo so these versions match.");
}
[Fact]
public void StandalonePublishWithLatestTFMUsesBundledAspNetCoreAppVersion()
{
var _testInstance = TestAssets.Get(AspNetTestProject)
.CreateInstance(identifier: LatestSupportedAspNetCoreAppVersion)
.WithSourceFiles();
string projectDirectory = _testInstance.Root.FullName;
string projectPath = Path.Combine(projectDirectory, $"{AspNetTestProject}.csproj");
var project = XDocument.Load(projectPath);
var ns = project.Root.Name.Namespace;
// Update TargetFramework to the right version of .NET Core
project.Root.Element(ns + "PropertyGroup")
.Element(ns + "TargetFramework")
.Value = "netcoreapp" + LatestSupportedAspNetCoreAppVersion;
var rid = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier();
// Set RuntimeIdentifier to simulate standalone publish
project.Root.Element(ns + "PropertyGroup")
.Add(new XElement(ns + "RuntimeIdentifier", rid));
project.Save(projectPath);
// Get the implicit version
new RestoreCommand()
.WithWorkingDirectory(projectDirectory)
.Execute()
.Should().Pass();
var assetsFilePath = Path.Combine(projectDirectory, "obj", "project.assets.json");
var assetsFile = new LockFileFormat().Read(assetsFilePath);
var restoredVersion = GetAspNetCoreAppVersion(assetsFile);
restoredVersion.Should().NotBeNull();
var bundledVersionPath = Path.Combine(projectDirectory, ".BundledAspNetCoreVersion");
var bundledVersion = File.ReadAllText(bundledVersionPath).Trim();
restoredVersion.ToNormalizedString().Should().BeEquivalentTo(bundledVersion,
"The bundled aspnetcore versions set in Microsoft.NETCoreSdk.BundledVersions.props should be idenitical to the versions set in DependencyVersions.props." +
"Please update MSBuildExtensions.targets in this repo so these versions match.");
}
[Theory]
[MemberData(nameof(SupportedAspNetCoreAppVersions))]
public void ItRollsForwardToTheLatestVersion(string minorVersion)
{
var _testInstance = TestAssets.Get(AspNetTestProject)
.CreateInstance(identifier: minorVersion)
.WithSourceFiles();
string projectDirectory = _testInstance.Root.FullName;
string projectPath = Path.Combine(projectDirectory, $"{AspNetTestProject}.csproj");
var project = XDocument.Load(projectPath);
var ns = project.Root.Name.Namespace;
// Update TargetFramework to the right version of .NET Core
project.Root.Element(ns + "PropertyGroup")
.Element(ns + "TargetFramework")
.Value = "netcoreapp" + minorVersion;
var rid = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier();
// Set RuntimeIdentifier to opt in to roll-forward behavior
project.Root.Element(ns + "PropertyGroup")
.Add(new XElement(ns + "RuntimeIdentifier", rid));
project.Save(projectPath);
// Get the version rolled forward to
new RestoreCommand()
.WithWorkingDirectory(projectDirectory)
.Execute()
.Should().Pass();
string assetsFilePath = Path.Combine(projectDirectory, "obj", "project.assets.json");
var assetsFile = new LockFileFormat().Read(assetsFilePath);
var rolledForwardVersion = GetAspNetCoreAppVersion(assetsFile);
rolledForwardVersion.Should().NotBeNull();
if (rolledForwardVersion.IsPrerelease)
{
// If this version of .NET Core is still prerelease, then:
// - Floating the patch by adding ".*" to the major.minor version won't work, but
// - There aren't any patches to roll-forward to, so we skip testing this until the version
// leaves prerelease.
return;
}
// Float the RuntimeFrameworkVersion to get the latest version of the runtime available from feeds
Directory.Delete(Path.Combine(projectDirectory, "obj"), true);
project.Root.Element(ns + "PropertyGroup")
.Add(new XElement(ns + "RuntimeFrameworkVersion", $"{minorVersion}.*"));
project.Save(projectPath);
new RestoreCommand()
.WithWorkingDirectory(projectDirectory)
.Execute()
.Should().Pass();
var floatedAssetsFile = new LockFileFormat().Read(assetsFilePath);
var floatedVersion = GetAspNetCoreAppVersion(floatedAssetsFile);
floatedVersion.Should().NotBeNull();
rolledForwardVersion.ToNormalizedString().Should().BeEquivalentTo(floatedVersion.ToNormalizedString(),
"the latest patch version properties in Microsoft.NETCoreSdk.BundledVersions.props need to be updated " +
"(see MSBuildExtensions.targets in this repo)");
}
[Fact]
public void WeCoverLatestAspNetCoreAppRollForward()
{
// Run "dotnet new web", get TargetFramework property, and make sure it's covered in SupportedAspNetCoreAppVersions
using (DisposableDirectory directory = Temp.CreateDirectory())
{
string projectDirectory = directory.Path;
new NewCommandShim()
.WithWorkingDirectory(projectDirectory)
.Execute("web --no-restore")
.Should().Pass();
string projectPath = Path.Combine(projectDirectory, Path.GetFileName(projectDirectory) + ".csproj");
var project = XDocument.Load(projectPath);
var ns = project.Root.Name.Namespace;
string targetFramework = project.Root.Element(ns + "PropertyGroup")
.Element(ns + "TargetFramework")
.Value;
SupportedAspNetCoreAppVersions.Select(v => $"netcoreapp{v[0]}")
.Should().Contain(targetFramework, $"the {nameof(SupportedAspNetCoreAppVersions)} property should include the default version " +
"of Microsoft.AspNetCore.App used by the templates created by \"dotnet new web\"");
}
}
private NuGetVersion GetAspNetCoreAppVersion(LockFile lockFile, bool portable = false)
{
return lockFile?.Targets?.SingleOrDefault(t => portable || t.RuntimeIdentifier != null)
?.Libraries?.SingleOrDefault(l =>
string.Compare(l.Name, "Microsoft.AspNetCore.App", StringComparison.CurrentCultureIgnoreCase) == 0)
?.Version;
}
public static string LatestSupportedAspNetCoreAppVersion = "2.1";
public static IEnumerable<object[]> SupportedAspNetCoreAppVersions
{
get
{
yield return new object[] { LatestSupportedAspNetCoreAppVersion };
}
}
}
}

View file

@ -0,0 +1,83 @@
// 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.IO;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
namespace Microsoft.DotNet.Tests.EndToEnd
{
public class GivenDotNetLinuxInstallers
{
[Fact]
public void ItHasExpectedDependencies()
{
var installerFile = Environment.GetEnvironmentVariable("SDK_INSTALLER_FILE");
if (string.IsNullOrEmpty(installerFile))
{
return;
}
var ext = Path.GetExtension(installerFile);
switch (ext)
{
case ".deb":
DebianPackageHasDependencyOnAspNetCoreStoreAndDotnetRuntime(installerFile);
return;
case ".rpm":
RpmPackageHasDependencyOnAspNetCoreStoreAndDotnetRuntime(installerFile);
return;
}
}
private void DebianPackageHasDependencyOnAspNetCoreStoreAndDotnetRuntime(string installerFile)
{
// Example output:
// $ dpkg --info dotnet-sdk-2.1.105-ubuntu-x64.deb
// new debian package, version 2.0.
// size 75660448 bytes: control archive=29107 bytes.
// 717 bytes, 11 lines control
// 123707 bytes, 1004 lines md5sums
// 1710 bytes, 28 lines * postinst #!/usr/bin/env
// Package: dotnet-sdk-2.1.104
// Version: 2.1.104-1
// Architecture: amd64
// Maintainer: Microsoft <dotnetcore@microsoft.com>
// Installed-Size: 201119
// Depends: dotnet-runtime-2.0.6, aspnetcore-store-2.0.6
// Section: devel
// Priority: standard
// Homepage: https://dotnet.github.io/core
// Description: Microsoft .NET Core SDK - 2.1.104
new TestCommand("dpkg")
.ExecuteWithCapturedOutput($"--info {installerFile}")
.Should().Pass()
.And.HaveStdOutMatching(@"Depends:.*\s?dotnet-runtime-\d+(\.\d+){2}")
.And.HaveStdOutMatching(@"Depends:.*\s?aspnetcore-store-\d+(\.\d+){2}");
}
private void RpmPackageHasDependencyOnAspNetCoreStoreAndDotnetRuntime(string installerFile)
{
// Example output:
// $ rpm -qpR dotnet-sdk-2.1.105-rhel-x64.rpm
// dotnet-runtime-2.0.7 >= 2.0.7
// aspnetcore-store-2.0.7 >= 2.0.7
// /bin/sh
// /bin/sh
// rpmlib(PayloadFilesHavePrefix) <= 4.0-1
// rpmlib(CompressedFileNames) <= 3.0.4-1
new TestCommand("rpm")
.ExecuteWithCapturedOutput($"-qpR {installerFile}")
.Should().Pass()
.And.HaveStdOutMatching(@"dotnet-runtime-\d+(\.\d+){2} >= \d+(\.\d+){2}")
.And.HaveStdOutMatching(@"aspnetcore-store-\d+(\.\d+){2} >= \d+(\.\d+){2}");
}
}
}

View file

@ -21,7 +21,7 @@
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="runtime.linux-x64.Microsoft.NETCore.DotNetHostResolver" Version="$(MicrosoftNETCoreDotNetHostResolverPackageVersion)" />
<PackageReference Include="runtime.osx-x64.Microsoft.NETCore.DotNetHostResolver" Version="$(MicrosoftNETCoreDotNetHostResolverPackageVersion)" />
<PackageReference Include="runtime.alpine.3.6-x64.Microsoft.NETCore.DotNetHostResolver" Version="$(MicrosoftNETCoreDotNetHostResolverPackageVersion)" />
<PackageReference Include="runtime.linux-musl-x64.Microsoft.NETCore.DotNetHostResolver" Version="$(MicrosoftNETCoreDotNetHostResolverPackageVersion)" />
</ItemGroup>
<ItemGroup>

View file

@ -14,4 +14,8 @@
<ProjectReference Include="..\..\src\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NETStandard.Library" Version="2.0.0" />
</ItemGroup>
</Project>

View file

@ -59,7 +59,9 @@
<testAssetSourceRoot>$(BaseOutputPath)/TestAsset/SampleGlobalTool</testAssetSourceRoot>
</PropertyGroup>
<Copy SourceFiles="SampleGlobalTool/DotnetToolSettings.xml" DestinationFolder="$(testAssetSourceRoot)" />
<MSBuild BuildInParallel="False" Projects="SampleGlobalTool/consoledemo.csproj" Targets="Restore;Build;Publish" Properties="Configuration=Release;BaseOutputPath=$(testAssetSourceRoot)/bin/">
<MSBuild BuildInParallel="False" Projects="SampleGlobalTool/consoledemo.csproj" Targets="Restore" Properties="Configuration=Release;BaseOutputPath=$(testAssetSourceRoot)/bin/;ForceRestoreToEvaluateSeparately=1">
</MSBuild>
<MSBuild BuildInParallel="False" Projects="SampleGlobalTool/consoledemo.csproj" Targets="Build;Publish" Properties="Configuration=Release;BaseOutputPath=$(testAssetSourceRoot)/bin/">
</MSBuild>
<MSBuild BuildInParallel="False" Projects="SampleGlobalTool/consoledemo.csproj" Targets="pack" Properties="Configuration=Release;NuspecFile=includepublish.nuspec;NuspecBasePath=$(testAssetSourceRoot);PackageOutputPath=$(OutputPath)/TestAssetLocalNugetFeed">
</MSBuild>
@ -72,7 +74,9 @@
<Copy SourceFiles="SampleGlobalToolWithShim/DotnetToolSettings.xml" DestinationFolder="$(testAssetSourceRoot)" />
<Copy SourceFiles="SampleGlobalToolWithShim/dummyshim" DestinationFolder="$(testAssetSourceRoot)" />
<Copy SourceFiles="SampleGlobalToolWithShim/dummyshim.exe" DestinationFolder="$(testAssetSourceRoot)" />
<MSBuild BuildInParallel="False" Projects="SampleGlobalToolWithShim/consoledemo.csproj" Targets="Restore;Build;Publish" Properties="Configuration=Release;BaseOutputPath=$(testAssetSourceRoot)/bin/">
<MSBuild BuildInParallel="False" Projects="SampleGlobalToolWithShim/consoledemo.csproj" Targets="Restore" Properties="Configuration=Release;BaseOutputPath=$(testAssetSourceRoot)/bin/;ForceRestoreToEvaluateSeparately=1">
</MSBuild>
<MSBuild BuildInParallel="False" Projects="SampleGlobalToolWithShim/consoledemo.csproj" Targets="Build;Publish" Properties="Configuration=Release;BaseOutputPath=$(testAssetSourceRoot)/bin/">
</MSBuild>
<MSBuild BuildInParallel="False" Projects="SampleGlobalToolWithShim/consoledemo.csproj" Targets="pack" Properties="Configuration=Release;NuspecFile=includepublish.nuspec;NuspecBasePath=$(testAssetSourceRoot);PackageOutputPath=$(OutputPath)/TestAssetLocalNugetFeed">
</MSBuild>

View file

@ -259,6 +259,50 @@ namespace Microsoft.DotNet.ToolPackage.Tests
package.Uninstall();
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void GivenARelativeSourcePathInstallSucceeds(bool testMockBehaviorIsInSync)
{
var source = GetTestLocalFeedPath();
var (store, installer, reporter, fileSystem) = Setup(
useMock: testMockBehaviorIsInSync,
feeds: GetMockFeedsForSource(source));
var package = installer.InstallPackage(
packageId: TestPackageId,
versionRange: VersionRange.Parse(TestPackageVersion),
targetFramework: _testTargetframework,
additionalFeeds: new[] { Path.GetRelativePath(Directory.GetCurrentDirectory(), source) });
AssertPackageInstall(reporter, fileSystem, package, store);
package.Uninstall();
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void GivenAUriSourceInstallSucceeds(bool testMockBehaviorIsInSync)
{
var source = GetTestLocalFeedPath();
var (store, installer, reporter, fileSystem) = Setup(
useMock: testMockBehaviorIsInSync,
feeds: GetMockFeedsForSource(source));
var package = installer.InstallPackage(
packageId: TestPackageId,
versionRange: VersionRange.Parse(TestPackageVersion),
targetFramework: _testTargetframework,
additionalFeeds: new[] { new Uri(source).AbsoluteUri });
AssertPackageInstall(reporter, fileSystem, package, store);
package.Uninstall();
}
[Theory]
[InlineData(false)]
[InlineData(true)]

View file

@ -0,0 +1,20 @@
// 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 Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Tools.Test.Utilities
{
public sealed class BuildServerCommand : DotnetCommand
{
public override CommandResult Execute(string args = "")
{
return base.Execute($"build-server {args}");
}
public override CommandResult ExecuteWithCapturedOutput(string args = "")
{
return base.ExecuteWithCapturedOutput($"build-server {args}");
}
}
}

View file

@ -15,7 +15,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
{
case "fedora.24-x64":
case "rhel.6-x64":
case "alpine.3.6-x64":
case "linux-musl-x64":
case "opensuse.42.1-x64":
case "ubuntu.16.10-x64":
case "linux-x64":
@ -28,7 +28,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
{
case "linux-x64":
case "rhel.6-x64":
case "alpine.3.6-x64":
case "linux-musl-x64":
return false;
}
}
@ -37,7 +37,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
switch (rid)
{
case "rhel.6-x64":
case "alpine.3.6-x64":
case "linux-musl-x64":
return false;
}
}

View file

@ -94,6 +94,11 @@ namespace Microsoft.Extensions.DependencyModel.Tests
int bufferSize,
FileOptions fileOptions)
{
if (fileMode == FileMode.Open && fileAccess == FileAccess.Read)
{
return OpenRead(path);
}
throw new NotImplementedException();
}
@ -166,7 +171,15 @@ namespace Microsoft.Extensions.DependencyModel.Tests
public IEnumerable<string> EnumerateFiles(string path, string searchPattern)
{
throw new NotImplementedException();
if (searchPattern != "*")
{
throw new NotImplementedException();
}
foreach (var kvp in _files.Where(kvp => kvp.Key != kvp.Value && Path.GetDirectoryName(kvp.Key) == path))
{
yield return kvp.Key;
}
}
public IEnumerable<string> EnumerateFileSystemEntries(string path)

View file

@ -1,27 +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.IO;
using System.Linq;
namespace Microsoft.DotNet.Tools.Test.Utilities
{
public class ProjectUtils
{
public static string GetProjectJson(string testRoot, string project)
{
// We assume that the project name same as the directory name with contains the project.json
// We can do better here by using ProjectReader to get the correct project name
string projectPath = Directory.GetFiles(testRoot, "project.json", SearchOption.AllDirectories)
.FirstOrDefault(pj => Directory.GetParent(pj).Name.Equals(project));
if (string.IsNullOrEmpty(projectPath))
{
throw new Exception($"Cannot file project '{project}' in '{testRoot}'");
}
return projectPath;
}
}
}

View file

@ -34,7 +34,7 @@ SDK commands:
sln Modify solution (SLN) files.
add Add reference to the project.
remove Remove reference from the project.
list List project references or installed tools.
list List references of a .NET project.
nuget Provides additional NuGet commands.
msbuild Runs Microsoft Build Engine (MSBuild).
vstest Runs Microsoft Test Execution Command Line Tool.
@ -60,7 +60,15 @@ runtime-options:
--additionalprobingpath <path> Path containing probing policy and assemblies to probe for.
--fx-version <version> Version of the installed Shared Framework to use to run the application.
--roll-forward-on-no-candidate-fx Roll forward on no candidate shared framework is enabled.
--additional-deps <path> Path to additional deps.json file.";
--additional-deps <path> Path to additional deps.json file.
Additional tools ('dotnet [tool-name] --help' for more information):
dev-certs Create and manage development certificates.
ef Entity Framework Core command-line tools.
sql-cache SQL Server cache command-line tools.
user-secrets Manage development user secrets.
watch Start a file watcher that runs a command when files change.
";
[Theory]
[InlineData("--help")]

View file

@ -0,0 +1,192 @@
// 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 FluentAssertions;
using Microsoft.DotNet.BuildServer;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Configurer;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.DependencyModel.Tests;
using Microsoft.Extensions.EnvironmentAbstractions;
using Moq;
using Xunit;
using LocalizableStrings = Microsoft.DotNet.BuildServer.LocalizableStrings;
namespace Microsoft.DotNet.Tests.BuildServerTests
{
public class BuildServerProviderTests
{
[Fact]
public void GivenMSBuildFlagItYieldsMSBuild()
{
var provider = new BuildServerProvider(
new FileSystemMockBuilder().Build(),
CreateEnvironmentProviderMock().Object);
provider
.EnumerateBuildServers(ServerEnumerationFlags.MSBuild)
.Select(s => s.Name)
.Should()
.Equal(LocalizableStrings.MSBuildServer);
}
[Fact]
public void GivenVBCSCompilerFlagItYieldsVBCSCompiler()
{
var provider = new BuildServerProvider(
new FileSystemMockBuilder().Build(),
CreateEnvironmentProviderMock().Object);
provider
.EnumerateBuildServers(ServerEnumerationFlags.VBCSCompiler)
.Select(s => s.Name)
.Should()
.Equal(LocalizableStrings.VBCSCompilerServer);
}
[Fact]
public void GivenRazorFlagAndNoPidDirectoryTheEnumerationIsEmpty()
{
var provider = new BuildServerProvider(
new FileSystemMockBuilder().Build(),
CreateEnvironmentProviderMock().Object);
provider
.EnumerateBuildServers(ServerEnumerationFlags.Razor)
.Should()
.BeEmpty();
}
[Fact]
public void GivenNoEnvironmentVariableItUsesTheDefaultPidDirectory()
{
var provider = new BuildServerProvider(
new FileSystemMockBuilder().Build(),
CreateEnvironmentProviderMock().Object);
provider
.GetPidFileDirectory()
.Value
.Should()
.Be(Path.Combine(
CliFolderPathCalculator.DotnetUserProfileFolderPath,
"pids",
"build"));
}
[Fact]
public void GivenEnvironmentVariableItUsesItForThePidDirectory()
{
const string PidDirectory = "path/to/some/directory";
var provider = new BuildServerProvider(
new FileSystemMockBuilder().Build(),
CreateEnvironmentProviderMock(PidDirectory).Object);
provider
.GetPidFileDirectory()
.Value
.Should()
.Be(PidDirectory);
}
[Fact]
public void GivenARazorPidFileItReturnsARazorBuildServer()
{
const int ProcessId = 1234;
const string ServerPath = "/path/to/rzc.dll";
const string PipeName = "some-pipe-name";
string pidDirectory = Path.GetFullPath("var/pids/build");
string pidFilePath = Path.Combine(pidDirectory, $"{RazorPidFile.FilePrefix}{ProcessId}");
var fileSystemMock = new FileSystemMockBuilder()
.AddFile(
pidFilePath,
$"{ProcessId}{Environment.NewLine}{RazorPidFile.RazorServerType}{Environment.NewLine}{ServerPath}{Environment.NewLine}{PipeName}")
.AddFile(
Path.Combine(pidDirectory, $"{RazorPidFile.FilePrefix}not-a-pid-file"),
"not-a-pid-file")
.Build();
var provider = new BuildServerProvider(
fileSystemMock,
CreateEnvironmentProviderMock(pidDirectory).Object);
var servers = provider.EnumerateBuildServers(ServerEnumerationFlags.Razor).ToArray();
servers.Length.Should().Be(1);
var razorServer = servers.First() as RazorServer;
razorServer.Should().NotBeNull();
razorServer.ProcessId.Should().Be(ProcessId);
razorServer.Name.Should().Be(LocalizableStrings.RazorServer);
razorServer.PidFile.Should().NotBeNull();
razorServer.PidFile.Path.Value.Should().Be(pidFilePath);
razorServer.PidFile.ProcessId.Should().Be(ProcessId);
razorServer.PidFile.ServerPath.Value.Should().Be(ServerPath);
razorServer.PidFile.PipeName.Should().Be(PipeName);
}
[Theory]
[InlineData(typeof(UnauthorizedAccessException))]
[InlineData(typeof(IOException))]
public void GivenAnExceptionAccessingTheRazorPidFileItPrintsAWarning(Type exceptionType)
{
const int ProcessId = 1234;
const string ErrorMessage = "failed!";
string pidDirectory = Path.GetFullPath("var/pids/build");
string pidFilePath = Path.Combine(pidDirectory, $"{RazorPidFile.FilePrefix}{ProcessId}");
var directoryMock = new Mock<IDirectory>();
directoryMock.Setup(d => d.Exists(pidDirectory)).Returns(true);
directoryMock.Setup(d => d.EnumerateFiles(pidDirectory, "*")).Returns(new [] { pidFilePath });
var fileMock = new Mock<IFile>();
fileMock
.Setup(f => f.OpenFile(
pidFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.Write | FileShare.Delete,
4096,
FileOptions.None))
.Throws((Exception)Activator.CreateInstance(exceptionType, new object[] { ErrorMessage } ));
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock.SetupGet(fs => fs.Directory).Returns(directoryMock.Object);
fileSystemMock.SetupGet(fs => fs.File).Returns(fileMock.Object);
var reporter = new BufferedReporter();
var provider = new BuildServerProvider(
fileSystemMock.Object,
CreateEnvironmentProviderMock(pidDirectory).Object,
reporter);
var servers = provider.EnumerateBuildServers(ServerEnumerationFlags.Razor).ToArray();
servers.Should().BeEmpty();
reporter.Lines.Should().Equal(
string.Format(
LocalizableStrings.FailedToReadPidFile,
pidFilePath,
ErrorMessage).Yellow());
}
private Mock<IEnvironmentProvider> CreateEnvironmentProviderMock(string value = null)
{
var provider = new Mock<IEnvironmentProvider>(MockBehavior.Strict);
provider
.Setup(p => p.GetEnvironmentVariable(BuildServerProvider.PidFileDirectoryVariableName))
.Returns(value);
return provider;
}
}
}

View file

@ -1,123 +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 System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Build.Exceptions;
using Microsoft.DotNet.BuildServer;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.EnvironmentAbstractions;
using Moq;
using NuGet.Frameworks;
using Xunit;
using LocalizableStrings = Microsoft.DotNet.BuildServer.LocalizableStrings;
namespace Microsoft.DotNet.Tests.BuildServerTests
{
public class RazorServerManagerTests
{
[Fact]
public async Task GivenNoRazorAssemblyShutdownIsSkipped()
{
var resolverMock = new Mock<IRazorAssemblyResolver>(MockBehavior.Strict);
resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Returns(new FilePath[] {});
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object);
var result = await manager.ShutdownServerAsync();
result.Kind.Should().Be(ResultKind.Skipped);
result.Message.Should().Be(LocalizableStrings.NoRazorProjectFound);
result.Exception.Should().BeNull();
}
[Fact]
public async Task GivenARazorAssemblyShutdownSucceeds()
{
const string FakeRazorAssemblyPath = "/path/to/razor.dll";
var resolverMock = new Mock<IRazorAssemblyResolver>(MockBehavior.Strict);
resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Returns(new FilePath[] { new FilePath(FakeRazorAssemblyPath) });
var commandMock = new Mock<ICommand>(MockBehavior.Strict);
commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object);
commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object);
commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 0, "", ""));
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
commandFactoryMock
.Setup(
f => f.Create(
"exec",
new string[] { FakeRazorAssemblyPath, "shutdown" },
It.IsAny<NuGetFramework>(),
Constants.DefaultConfiguration))
.Returns(commandMock.Object);
var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object);
var result = await manager.ShutdownServerAsync();
result.Kind.Should().Be(ResultKind.Success);
result.Message.Should().BeNull();
result.Exception.Should().BeNull();
}
[Fact]
public async Task GivenAnInvalidProjectFileShutdownFails()
{
var exception = new InvalidProjectFileException("invalid project!");
var resolverMock = new Mock<IRazorAssemblyResolver>(MockBehavior.Strict);
resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Throws(exception);
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object);
var result = await manager.ShutdownServerAsync();
result.Kind.Should().Be(ResultKind.Failure);
result.Message.Should().Be(exception.Message);
result.Exception.Should().Be(exception);
}
[Fact]
public async Task GivenANonZeroExitCodeShutdownFails()
{
const string FakeRazorAssemblyPath = "/path/to/razor.dll";
const string ErrorMessage = "failed!";
var resolverMock = new Mock<IRazorAssemblyResolver>(MockBehavior.Strict);
resolverMock.Setup(r => r.EnumerateRazorToolAssemblies()).Returns(new FilePath[] { new FilePath(FakeRazorAssemblyPath) });
var commandMock = new Mock<ICommand>(MockBehavior.Strict);
commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object);
commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object);
commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 1, "", ErrorMessage));
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
commandFactoryMock
.Setup(
f => f.Create(
"exec",
new string[] { FakeRazorAssemblyPath, "shutdown" },
It.IsAny<NuGetFramework>(),
Constants.DefaultConfiguration))
.Returns(commandMock.Object);
var manager = new RazorServerManager(resolverMock.Object, commandFactoryMock.Object);
var result = await manager.ShutdownServerAsync();
result.Kind.Should().Be(ResultKind.Failure);
result.Message.Should().Be(ErrorMessage);
result.Exception.Should().BeNull();
}
}
}

View file

@ -0,0 +1,109 @@
// 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.IO;
using System.Linq;
using FluentAssertions;
using Microsoft.DotNet.BuildServer;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools;
using Microsoft.Extensions.DependencyModel.Tests;
using Microsoft.Extensions.EnvironmentAbstractions;
using Moq;
using NuGet.Frameworks;
using Xunit;
using LocalizableStrings = Microsoft.DotNet.BuildServer.LocalizableStrings;
namespace Microsoft.DotNet.Tests.BuildServerTests
{
public class RazorServerTests
{
[Fact]
public void GivenAFailedShutdownCommandItThrows()
{
const int ProcessId = 1234;
const string ServerPath = "path/to/rzc.dll";
const string PipeName = "some-pipe-name";
const string ErrorMessage = "error!";
string pidDirectory = Path.GetFullPath("var/pids/build");
string pidFilePath = Path.Combine(pidDirectory, $"{RazorPidFile.FilePrefix}{ProcessId}");
var fileSystemMock = new FileSystemMockBuilder()
.AddFile(pidFilePath, "")
.Build();
fileSystemMock.File.Exists(pidFilePath).Should().BeTrue();
var server = new RazorServer(
pidFile: new RazorPidFile(
path: new FilePath(pidFilePath),
processId: ProcessId,
serverPath: new FilePath(ServerPath),
pipeName: PipeName),
commandFactory: CreateCommandFactoryMock(ServerPath, PipeName, exitCode: 1, stdErr: ErrorMessage).Object,
fileSystem: fileSystemMock);
Action a = () => server.Shutdown();
a.ShouldThrow<BuildServerException>().WithMessage(
string.Format(
LocalizableStrings.ShutdownCommandFailed,
ErrorMessage));
fileSystemMock.File.Exists(pidFilePath).Should().BeTrue();
}
[Fact]
public void GivenASuccessfulShutdownItDoesNotThrow()
{
const int ProcessId = 1234;
const string ServerPath = "path/to/rzc.dll";
const string PipeName = "some-pipe-name";
string pidDirectory = Path.GetFullPath("var/pids/build");
string pidFilePath = Path.Combine(pidDirectory, $"{RazorPidFile.FilePrefix}{ProcessId}");
var fileSystemMock = new FileSystemMockBuilder()
.AddFile(pidFilePath, "")
.Build();
fileSystemMock.File.Exists(pidFilePath).Should().BeTrue();
var server = new RazorServer(
pidFile: new RazorPidFile(
path: new FilePath(pidFilePath),
processId: ProcessId,
serverPath: new FilePath(ServerPath),
pipeName: PipeName),
commandFactory: CreateCommandFactoryMock(ServerPath, PipeName).Object,
fileSystem: fileSystemMock);
server.Shutdown();
fileSystemMock.File.Exists(pidFilePath).Should().BeFalse();
}
private Mock<ICommandFactory> CreateCommandFactoryMock(string serverPath, string pipeName, int exitCode = 0, string stdErr = "")
{
var commandMock = new Mock<ICommand>(MockBehavior.Strict);
commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object);
commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object);
commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, exitCode, "", stdErr));
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
commandFactoryMock
.Setup(
f => f.Create(
"exec",
new string[] { serverPath, "shutdown", "-w", "-p", pipeName },
It.IsAny<NuGetFramework>(),
Constants.DefaultConfiguration))
.Returns(commandMock.Object);
return commandFactoryMock;
}
}
}

View file

@ -1,75 +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.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.DotNet.BuildServer;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools;
using Microsoft.Extensions.EnvironmentAbstractions;
using Moq;
using NuGet.Frameworks;
using Xunit;
namespace Microsoft.DotNet.Tests.BuildServerTests
{
public class VBCSCompilerServerManagerTests
{
[Fact]
public async Task GivenAZeroExit()
{
var commandMock = new Mock<ICommand>(MockBehavior.Strict);
commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object);
commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object);
commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 0, "", ""));
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
commandFactoryMock
.Setup(
f => f.Create(
"exec",
new string[] { VBCSCompilerServerManager.VBCSCompilerPath, "-shutdown" },
It.IsAny<NuGetFramework>(),
Constants.DefaultConfiguration))
.Returns(commandMock.Object);
var manager = new VBCSCompilerServerManager(commandFactoryMock.Object);
var result = await manager.ShutdownServerAsync();
result.Kind.Should().Be(ResultKind.Success);
result.Message.Should().BeNull();
result.Exception.Should().BeNull();
}
[Fact]
public async Task GivenANonZeroExitCodeShutdownFails()
{
const string ErrorMessage = "failed!";
var commandMock = new Mock<ICommand>(MockBehavior.Strict);
commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object);
commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object);
commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, 1, "", ErrorMessage));
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
commandFactoryMock
.Setup(
f => f.Create(
"exec",
new string[] { VBCSCompilerServerManager.VBCSCompilerPath, "-shutdown" },
It.IsAny<NuGetFramework>(),
Constants.DefaultConfiguration))
.Returns(commandMock.Object);
var manager = new VBCSCompilerServerManager(commandFactoryMock.Object);
var result = await manager.ShutdownServerAsync();
result.Kind.Should().Be(ResultKind.Failure);
result.Message.Should().Be(ErrorMessage);
result.Exception.Should().BeNull();
}
}
}

View file

@ -0,0 +1,63 @@
// 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.Linq;
using FluentAssertions;
using Microsoft.DotNet.BuildServer;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools;
using Microsoft.Extensions.EnvironmentAbstractions;
using Moq;
using NuGet.Frameworks;
using Xunit;
using LocalizableStrings = Microsoft.DotNet.BuildServer.LocalizableStrings;
namespace Microsoft.DotNet.Tests.BuildServerTests
{
public class VBCSCompilerServerTests
{
[Fact]
public void GivenAZeroExitShutdownDoesNotThrow()
{
var server = new VBCSCompilerServer(CreateCommandFactoryMock().Object);
server.Shutdown();
}
[Fact]
public void GivenANonZeroExitCodeShutdownThrows()
{
const string ErrorMessage = "failed!";
var server = new VBCSCompilerServer(CreateCommandFactoryMock(exitCode: 1, stdErr: ErrorMessage).Object);
Action a = () => server.Shutdown();
a.ShouldThrow<BuildServerException>().WithMessage(
string.Format(
LocalizableStrings.ShutdownCommandFailed,
ErrorMessage));
}
private Mock<ICommandFactory> CreateCommandFactoryMock(int exitCode = 0, string stdErr = "")
{
var commandMock = new Mock<ICommand>(MockBehavior.Strict);
commandMock.Setup(c => c.CaptureStdOut()).Returns(commandMock.Object);
commandMock.Setup(c => c.CaptureStdErr()).Returns(commandMock.Object);
commandMock.Setup(c => c.Execute()).Returns(new CommandResult(null, exitCode, "", stdErr));
var commandFactoryMock = new Mock<ICommandFactory>(MockBehavior.Strict);
commandFactoryMock
.Setup(
f => f.Create(
"exec",
new string[] { VBCSCompilerServer.VBCSCompilerPath, "-shutdown" },
It.IsAny<NuGetFramework>(),
Constants.DefaultConfiguration))
.Returns(commandMock.Object);
return commandFactoryMock;
}
}
}

View file

@ -5,78 +5,116 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.DotNet.BuildServer;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.TestFramework;
using Microsoft.DotNet.Tools.BuildServer;
using Microsoft.DotNet.Tools.BuildServer.Shutdown;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.EnvironmentAbstractions;
using Moq;
using Xunit;
using Parser = Microsoft.DotNet.Cli.Parser;
using CommandLocalizableStrings = Microsoft.DotNet.BuildServer.LocalizableStrings;
using LocalizableStrings = Microsoft.DotNet.Tools.BuildServer.Shutdown.LocalizableStrings;
using TestBuildServerCommand = Microsoft.DotNet.Tools.Test.Utilities.BuildServerCommand;
namespace Microsoft.DotNet.Tests.Commands
{
public class BuildServerShutdownCommandTests
public class BuildServerShutdownCommandTests : TestBase
{
private readonly BufferedReporter _reporter = new BufferedReporter();
[Fact]
public void GivenNoOptionsAllManagersArePresent()
public void GivenNoOptionsItEnumeratesAllServers()
{
var command = CreateCommand();
var provider = new Mock<IBuildServerProvider>(MockBehavior.Strict);
command.Managers.Select(m => m.ServerName).Should().Equal(
DotNet.BuildServer.LocalizableStrings.MSBuildServer,
DotNet.BuildServer.LocalizableStrings.VBCSCompilerServer,
DotNet.BuildServer.LocalizableStrings.RazorServer
);
provider
.Setup(p => p.EnumerateBuildServers(ServerEnumerationFlags.All))
.Returns(Array.Empty<IBuildServer>());
var command = CreateCommand(serverProvider: provider.Object);
command.Execute().Should().Be(0);
_reporter.Lines.Should().Equal(LocalizableStrings.NoServersToShutdown.Green());
provider.Verify(p => p.EnumerateBuildServers(ServerEnumerationFlags.All), Times.Once);
}
[Fact]
public void GivenMSBuildOptionOnlyItIsTheOnlyManager()
public void GivenMSBuildOptionOnlyItEnumeratesOnlyMSBuildServers()
{
var command = CreateCommand("--msbuild");
var provider = new Mock<IBuildServerProvider>(MockBehavior.Strict);
command.Managers.Select(m => m.ServerName).Should().Equal(
DotNet.BuildServer.LocalizableStrings.MSBuildServer
);
provider
.Setup(p => p.EnumerateBuildServers(ServerEnumerationFlags.MSBuild))
.Returns(Array.Empty<IBuildServer>());
var command = CreateCommand(options: "--msbuild", serverProvider: provider.Object);
command.Execute().Should().Be(0);
_reporter.Lines.Should().Equal(LocalizableStrings.NoServersToShutdown.Green());
provider.Verify(p => p.EnumerateBuildServers(ServerEnumerationFlags.MSBuild), Times.Once);
}
[Fact]
public void GivenVBCSCompilerOptionOnlyItIsTheOnlyManager()
public void GivenVBCSCompilerOptionOnlyItEnumeratesOnlyVBCSCompilers()
{
var command = CreateCommand("--vbcscompiler");
var provider = new Mock<IBuildServerProvider>(MockBehavior.Strict);
command.Managers.Select(m => m.ServerName).Should().Equal(
DotNet.BuildServer.LocalizableStrings.VBCSCompilerServer
);
provider
.Setup(p => p.EnumerateBuildServers(ServerEnumerationFlags.VBCSCompiler))
.Returns(Array.Empty<IBuildServer>());
var command = CreateCommand(options: "--vbcscompiler", serverProvider: provider.Object);
command.Execute().Should().Be(0);
_reporter.Lines.Should().Equal(LocalizableStrings.NoServersToShutdown.Green());
provider.Verify(p => p.EnumerateBuildServers(ServerEnumerationFlags.VBCSCompiler), Times.Once);
}
[Fact]
public void GivenRazorOptionOnlyItIsTheOnlyManager()
public void GivenRazorOptionOnlyItEnumeratesOnlyRazorServers()
{
var command = CreateCommand("--razor");
var provider = new Mock<IBuildServerProvider>(MockBehavior.Strict);
command.Managers.Select(m => m.ServerName).Should().Equal(
DotNet.BuildServer.LocalizableStrings.RazorServer
);
provider
.Setup(p => p.EnumerateBuildServers(ServerEnumerationFlags.Razor))
.Returns(Array.Empty<IBuildServer>());
var command = CreateCommand(options: "--razor", serverProvider: provider.Object);
command.Execute().Should().Be(0);
_reporter.Lines.Should().Equal(LocalizableStrings.NoServersToShutdown.Green());
provider.Verify(p => p.EnumerateBuildServers(ServerEnumerationFlags.Razor), Times.Once);
}
[Fact]
public void GivenSuccessfulShutdownsItPrintsSuccess()
{
var mocks = new[] {
CreateManagerMock("first", new Result(ResultKind.Success)),
CreateManagerMock("second", new Result(ResultKind.Success)),
CreateManagerMock("third", new Result(ResultKind.Success))
CreateServerMock("first"),
CreateServerMock("second"),
CreateServerMock("third")
};
var command = CreateCommand(managers: mocks.Select(m => m.Object));
var provider = new Mock<IBuildServerProvider>(MockBehavior.Strict);
provider
.Setup(p => p.EnumerateBuildServers(ServerEnumerationFlags.All))
.Returns(mocks.Select(m => m.Object));
var command = CreateCommand(serverProvider: provider.Object);
command.Execute().Should().Be(0);
@ -94,15 +132,21 @@ namespace Microsoft.DotNet.Tests.Commands
[Fact]
public void GivenAFailingShutdownItPrintsFailureMessage()
{
const string FailureMessage = "failed!";
const string FirstFailureMessage = "first failed!";
const string ThirdFailureMessage = "third failed!";
var mocks = new[] {
CreateManagerMock("first", new Result(ResultKind.Success)),
CreateManagerMock("second", new Result(ResultKind.Failure, FailureMessage)),
CreateManagerMock("third", new Result(ResultKind.Success))
CreateServerMock("first", exceptionMessage: FirstFailureMessage),
CreateServerMock("second"),
CreateServerMock("third", exceptionMessage: ThirdFailureMessage)
};
var command = CreateCommand(managers: mocks.Select(m => m.Object));
var provider = new Mock<IBuildServerProvider>(MockBehavior.Strict);
provider
.Setup(p => p.EnumerateBuildServers(ServerEnumerationFlags.All))
.Returns(mocks.Select(m => m.Object));
var command = CreateCommand(serverProvider: provider.Object);
command.Execute().Should().Be(1);
@ -110,113 +154,117 @@ namespace Microsoft.DotNet.Tests.Commands
FormatShuttingDownMessage(mocks[0].Object),
FormatShuttingDownMessage(mocks[1].Object),
FormatShuttingDownMessage(mocks[2].Object),
FormatSuccessMessage(mocks[0].Object),
FormatFailureMessage(mocks[1].Object, FailureMessage),
FormatSuccessMessage(mocks[2].Object));
VerifyShutdownCalls(mocks);
}
[Fact]
public void GivenASkippedShutdownItPrintsSkipMessage()
{
const string SkipMessage = "skipped!";
var mocks = new[] {
CreateManagerMock("first", new Result(ResultKind.Success)),
CreateManagerMock("second", new Result(ResultKind.Success)),
CreateManagerMock("third", new Result(ResultKind.Skipped, SkipMessage))
};
var command = CreateCommand(managers: mocks.Select(m => m.Object));
command.Execute().Should().Be(0);
_reporter.Lines.Should().Equal(
FormatShuttingDownMessage(mocks[0].Object),
FormatShuttingDownMessage(mocks[1].Object),
FormatShuttingDownMessage(mocks[2].Object),
FormatSuccessMessage(mocks[0].Object),
FormatFailureMessage(mocks[0].Object, FirstFailureMessage),
FormatSuccessMessage(mocks[1].Object),
FormatSkippedMessage(mocks[2].Object, SkipMessage));
FormatFailureMessage(mocks[2].Object, ThirdFailureMessage));
VerifyShutdownCalls(mocks);
}
[Fact]
public void GivenSuccessFailureAndSkippedItPrintsAllThree()
public void GivenARunningRazorServerItShutsDownSuccessfully()
{
const string FailureMessage = "failed!";
const string SkipMessage = "skipped!";
var pipeName = Path.GetRandomFileName();
var pidDirectory = Path.GetFullPath(Path.Combine(TempRoot.Root, Path.GetRandomFileName()));
var mocks = new[] {
CreateManagerMock("first", new Result(ResultKind.Success)),
CreateManagerMock("second", new Result(ResultKind.Failure, FailureMessage)),
CreateManagerMock("third", new Result(ResultKind.Skipped, SkipMessage))
};
var testInstance = TestAssets.Get("TestRazorApp")
.CreateInstance()
.WithSourceFiles();
var command = CreateCommand(managers: mocks.Select(m => m.Object));
new BuildCommand()
.WithWorkingDirectory(testInstance.Root)
.WithEnvironmentVariable(BuildServerProvider.PidFileDirectoryVariableName, pidDirectory)
.Execute($"/p:_RazorBuildServerPipeName={pipeName}")
.Should()
.Pass();
command.Execute().Should().Be(1);
var files = Directory.GetFiles(pidDirectory, RazorPidFile.FilePrefix + "*");
files.Length.Should().Be(1);
_reporter.Lines.Should().Equal(
FormatShuttingDownMessage(mocks[0].Object),
FormatShuttingDownMessage(mocks[1].Object),
FormatShuttingDownMessage(mocks[2].Object),
FormatSuccessMessage(mocks[0].Object),
FormatFailureMessage(mocks[1].Object, FailureMessage),
FormatSkippedMessage(mocks[2].Object, SkipMessage));
var pidFile = RazorPidFile.Read(new FilePath(files.First()));
pidFile.PipeName.Should().Be(pipeName);
VerifyShutdownCalls(mocks);
new TestBuildServerCommand()
.WithWorkingDirectory(testInstance.Root)
.WithEnvironmentVariable(BuildServerProvider.PidFileDirectoryVariableName, pidDirectory)
.ExecuteWithCapturedOutput("shutdown --razor")
.Should()
.Pass()
.And
.HaveStdOutContaining(
string.Format(
LocalizableStrings.ShutDownSucceededWithPid,
CommandLocalizableStrings.RazorServer,
pidFile.ProcessId));
}
private BuildServerShutdownCommand CreateCommand(string options = "", IEnumerable<IBuildServerManager> managers = null)
private BuildServerShutdownCommand CreateCommand(
string options = "",
IBuildServerProvider serverProvider = null,
IEnumerable<IBuildServer> buildServers = null,
ServerEnumerationFlags expectedFlags = ServerEnumerationFlags.None)
{
ParseResult result = Parser.Instance.Parse("dotnet build-server shutdown " + options);
return new BuildServerShutdownCommand(
options: result["dotnet"]["build-server"]["shutdown"],
result: result,
managers: managers,
serverProvider: serverProvider,
useOrderedWait: true,
reporter: _reporter);
}
private Mock<IBuildServerManager> CreateManagerMock(string serverName, Result result)
private Mock<IBuildServer> CreateServerMock(string name, int pid = 0, string exceptionMessage = null)
{
var mock = new Mock<IBuildServerManager>(MockBehavior.Strict);
var mock = new Mock<IBuildServer>(MockBehavior.Strict);
mock.SetupGet(m => m.ServerName).Returns(serverName);
mock.Setup(m => m.ShutdownServerAsync()).Returns(Task.FromResult(result));
mock.SetupGet(s => s.ProcessId).Returns(pid);
mock.SetupGet(s => s.Name).Returns(name);
if (exceptionMessage == null)
{
mock.Setup(s => s.Shutdown());
}
else
{
mock.Setup(s => s.Shutdown()).Throws(new Exception(exceptionMessage));
}
return mock;
}
private void VerifyShutdownCalls(IEnumerable<Mock<IBuildServerManager>> mocks)
private void VerifyShutdownCalls(IEnumerable<Mock<IBuildServer>> mocks)
{
foreach (var mock in mocks)
{
mock.Verify(m => m.ShutdownServerAsync(), Times.Once());
mock.Verify(s => s.Shutdown(), Times.Once);
}
}
private static string FormatShuttingDownMessage(IBuildServerManager manager)
private static string FormatShuttingDownMessage(IBuildServer server)
{
return string.Format(LocalizableStrings.ShuttingDownServer, manager.ServerName);
if (server.ProcessId != 0)
{
return string.Format(LocalizableStrings.ShuttingDownServerWithPid, server.Name, server.ProcessId);
}
return string.Format(LocalizableStrings.ShuttingDownServer, server.Name);
}
private static string FormatSuccessMessage(IBuildServerManager manager)
private static string FormatSuccessMessage(IBuildServer server)
{
return string.Format(LocalizableStrings.ShutDownSucceeded, manager.ServerName).Green();
if (server.ProcessId != 0)
{
return string.Format(LocalizableStrings.ShutDownSucceededWithPid, server.Name, server.ProcessId).Green();
}
return string.Format(LocalizableStrings.ShutDownSucceeded, server.Name).Green();
}
private static string FormatFailureMessage(IBuildServerManager manager, string message)
private static string FormatFailureMessage(IBuildServer server, string message)
{
return string.Format(LocalizableStrings.ShutDownFailed, manager.ServerName, message).Red();
}
private static string FormatSkippedMessage(IBuildServerManager manager, string message)
{
return string.Format(LocalizableStrings.ShutDownSkipped, manager.ServerName, message).Cyan();
if (server.ProcessId != 0)
{
return string.Format(LocalizableStrings.ShutDownFailedWithPid, server.Name, server.ProcessId, message).Red();
}
return string.Format(LocalizableStrings.ShutDownFailed, server.Name, message).Red();
}
}
}

View file

@ -85,10 +85,10 @@ namespace Microsoft.DotNet.Tests.Commands
public void WhenRunWithPackageIdWithSourceItShouldCreateValidShim()
{
const string sourcePath = "http://mysouce.com";
ParseResult result = Parser.Instance.Parse($"dotnet tool install -g {PackageId} --source-feed {sourcePath}");
ParseResult result = Parser.Instance.Parse($"dotnet tool install -g {PackageId} --add-source {sourcePath}");
AppliedOption appliedCommand = result["dotnet"]["tool"]["install"];
ParseResult parseResult =
Parser.Instance.ParseFrom("dotnet tool", new[] { "install", "-g", PackageId, "--source-feed", sourcePath });
Parser.Instance.ParseFrom("dotnet tool", new[] { "install", "-g", PackageId, "--add-source", sourcePath });
var toolToolPackageInstaller = CreateToolPackageInstaller(
@ -175,9 +175,11 @@ namespace Microsoft.DotNet.Tests.Commands
[Fact]
public void GivenFailedPackageInstallWhenRunWithPackageIdItShouldFail()
{
const string ErrorMessage = "Simulated error";
var toolPackageInstaller =
CreateToolPackageInstaller(
installCallback: () => throw new ToolPackageException("Simulated error"));
installCallback: () => throw new ToolPackageException(ErrorMessage));
var installCommand = new ToolInstallCommand(
_appliedCommand,
@ -191,8 +193,9 @@ namespace Microsoft.DotNet.Tests.Commands
a.ShouldThrow<GracefulException>().And.Message
.Should().Contain(
"Simulated error" + Environment.NewLine
+ string.Format(LocalizableStrings.ToolInstallationFailed, PackageId));
ErrorMessage +
Environment.NewLine +
string.Format(LocalizableStrings.ToolInstallationFailedWithRestoreGuidance, PackageId));
_fileSystem.Directory.Exists(Path.Combine(PathToPlacePackages, PackageId)).Should().BeFalse();
}

View file

@ -55,10 +55,10 @@ namespace Microsoft.DotNet.Tests.ParserTests
const string expectedSourceValue = "TestSourceValue";
var result =
Parser.Instance.Parse($"dotnet tool install -g --source-feed {expectedSourceValue} console.test.app");
Parser.Instance.Parse($"dotnet tool install -g --add-source {expectedSourceValue} console.test.app");
var appliedOptions = result["dotnet"]["tool"]["install"];
appliedOptions.ValueOrDefault<string[]>("source-feed").First().Should().Be(expectedSourceValue);
appliedOptions.ValueOrDefault<string[]>("add-source").First().Should().Be(expectedSourceValue);
}
[Fact]
@ -70,13 +70,13 @@ namespace Microsoft.DotNet.Tests.ParserTests
var result =
Parser.Instance.Parse(
$"dotnet tool install -g " +
$"--source-feed {expectedSourceValue1} " +
$"--source-feed {expectedSourceValue2} console.test.app");
$"--add-source {expectedSourceValue1} " +
$"--add-source {expectedSourceValue2} console.test.app");
var appliedOptions = result["dotnet"]["tool"]["install"];
appliedOptions.ValueOrDefault<string[]>("source-feed")[0].Should().Be(expectedSourceValue1);
appliedOptions.ValueOrDefault<string[]>("source-feed")[1].Should().Be(expectedSourceValue2);
appliedOptions.ValueOrDefault<string[]>("add-source")[0].Should().Be(expectedSourceValue1);
appliedOptions.ValueOrDefault<string[]>("add-source")[1].Should().Be(expectedSourceValue2);
}
[Fact]

View file

@ -62,10 +62,10 @@ namespace Microsoft.DotNet.Tests.ParserTests
const string expectedSourceValue = "TestSourceValue";
var result =
Parser.Instance.Parse($"dotnet tool update -g --source-feed {expectedSourceValue} console.test.app");
Parser.Instance.Parse($"dotnet tool update -g --add-source {expectedSourceValue} console.test.app");
var appliedOptions = result["dotnet"]["tool"]["update"];
appliedOptions.ValueOrDefault<string[]>("source-feed").First().Should().Be(expectedSourceValue);
appliedOptions.ValueOrDefault<string[]>("add-source").First().Should().Be(expectedSourceValue);
}
[Fact]
@ -77,13 +77,13 @@ namespace Microsoft.DotNet.Tests.ParserTests
var result =
Parser.Instance.Parse(
$"dotnet tool update -g " +
$"--source-feed {expectedSourceValue1} " +
$"--source-feed {expectedSourceValue2} console.test.app");
$"--add-source {expectedSourceValue1} " +
$"--add-source {expectedSourceValue2} console.test.app");
var appliedOptions = result["dotnet"]["tool"]["update"];
appliedOptions.ValueOrDefault<string[]>("source-feed")[0].Should().Be(expectedSourceValue1);
appliedOptions.ValueOrDefault<string[]>("source-feed")[1].Should().Be(expectedSourceValue2);
appliedOptions.ValueOrDefault<string[]>("add-source")[0].Should().Be(expectedSourceValue1);
appliedOptions.ValueOrDefault<string[]>("add-source")[1].Should().Be(expectedSourceValue2);
}
[Fact]