Implement Razor server discovery by pid file.
Previously, Razor server discovery for the `build-server shutdown` command was implemented by invoking MSBuild on a project file in the current directory to evaluate the path to the Razor server dll. This was problematic since it would only discover a single running Razor server instance and required that the user run the `build-server shutdown` command from a specific location. Razor's server now writes a "pid file" to a well-known location (`~/.dotnet/pids/build`) which the command can now enumerate to discover, and shutdown, the running Razor servers. This commit changes the Razor server discovery to use the pid files and removes the requirement that users need to run the command in specific directories to work. Fixes #9084.
This commit is contained in:
parent
8e01912b36
commit
1ade191cb6
49 changed files with 1115 additions and 716 deletions
22
src/dotnet/BuildServer/BuildServerException.cs
Normal file
22
src/dotnet/BuildServer/BuildServerException.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class BuildServerException : Exception
|
||||
{
|
||||
public BuildServerException()
|
||||
{
|
||||
}
|
||||
|
||||
public BuildServerException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public BuildServerException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
86
src/dotnet/BuildServer/BuildServerProvider.cs
Normal file
86
src/dotnet/BuildServer/BuildServerProvider.cs
Normal file
|
@ -0,0 +1,86 @@
|
|||
// 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.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Configurer;
|
||||
using Microsoft.Extensions.EnvironmentAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class BuildServerProvider : IBuildServerProvider
|
||||
{
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IEnvironmentProvider _environmentProvider;
|
||||
|
||||
public BuildServerProvider(
|
||||
IFileSystem fileSystem = null,
|
||||
IEnvironmentProvider environmentProvider = null)
|
||||
{
|
||||
_fileSystem = fileSystem ?? FileSystemWrapper.Default;
|
||||
_environmentProvider = environmentProvider ?? new EnvironmentProvider();
|
||||
}
|
||||
|
||||
public IEnumerable<IBuildServer> EnumerateBuildServers(ServerEnumerationFlags flags = ServerEnumerationFlags.All)
|
||||
{
|
||||
if ((flags & ServerEnumerationFlags.MSBuild) == ServerEnumerationFlags.MSBuild)
|
||||
{
|
||||
// Yield a single MSBuild server (handles server discovery itself)
|
||||
// TODO: use pid file enumeration when supported by the server (https://github.com/dotnet/cli/issues/9113)
|
||||
yield return new MSBuildServer();
|
||||
}
|
||||
|
||||
if ((flags & ServerEnumerationFlags.VBCSCompiler) == ServerEnumerationFlags.VBCSCompiler)
|
||||
{
|
||||
// Yield a single VB/C# compiler (handles server discovery itself)
|
||||
// TODO: use pid file enumeration when supported by the server (https://github.com/dotnet/cli/issues/9112)
|
||||
yield return new VBCSCompilerServer();
|
||||
}
|
||||
|
||||
// TODO: remove or amend this check when the following issues are resolved:
|
||||
// https://github.com/dotnet/cli/issues/9112
|
||||
// https://github.com/dotnet/cli/issues/9113
|
||||
if ((flags & ServerEnumerationFlags.Razor) != ServerEnumerationFlags.Razor)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var directory = GetPidFileDirectory();
|
||||
|
||||
if (!_fileSystem.Directory.Exists(directory.Value))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var path in _fileSystem.Directory.EnumerateFiles(directory.Value, "*"))
|
||||
{
|
||||
if ((flags & ServerEnumerationFlags.Razor) == ServerEnumerationFlags.Razor &&
|
||||
Path.GetFileName(path).StartsWith(RazorPidFile.FilePrefix))
|
||||
{
|
||||
var file = RazorPidFile.Read(new FilePath(path), _fileSystem);
|
||||
if (file != null)
|
||||
{
|
||||
yield return new RazorServer(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DirectoryPath GetPidFileDirectory()
|
||||
{
|
||||
var directory = _environmentProvider.GetEnvironmentVariable("DOTNET_BUILD_PIDFILE_DIRECTORY");
|
||||
if (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
return new DirectoryPath(directory);
|
||||
}
|
||||
|
||||
return new DirectoryPath(
|
||||
Path.Combine(
|
||||
CliFolderPathCalculator.DotnetUserProfileFolderPath,
|
||||
"pids",
|
||||
"build"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,10 +6,12 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal interface IBuildServerManager
|
||||
internal interface IBuildServer
|
||||
{
|
||||
string ServerName { get; }
|
||||
int ProcessId { get; }
|
||||
|
||||
Task<Result> ShutdownServerAsync();
|
||||
string Name { get; }
|
||||
|
||||
void Shutdown();
|
||||
}
|
||||
}
|
23
src/dotnet/BuildServer/IBuildServerProvider.cs
Normal file
23
src/dotnet/BuildServer/IBuildServerProvider.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
[Flags]
|
||||
internal enum ServerEnumerationFlags
|
||||
{
|
||||
None = 0,
|
||||
MSBuild = 1,
|
||||
VBCSCompiler = 2,
|
||||
Razor = 4,
|
||||
All = MSBuild | VBCSCompiler | Razor
|
||||
}
|
||||
|
||||
internal interface IBuildServerProvider
|
||||
{
|
||||
IEnumerable<IBuildServer> EnumerateBuildServers(ServerEnumerationFlags flags = ServerEnumerationFlags.All);
|
||||
}
|
||||
}
|
|
@ -1,14 +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 Microsoft.Extensions.EnvironmentAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal interface IRazorAssemblyResolver
|
||||
{
|
||||
IEnumerable<FilePath> EnumerateRazorToolAssemblies();
|
||||
}
|
||||
}
|
|
@ -126,7 +126,7 @@
|
|||
<data name="RazorServer" xml:space="preserve">
|
||||
<value>Razor build server</value>
|
||||
</data>
|
||||
<data name="NoRazorProjectFound" xml:space="preserve">
|
||||
<value>a Razor project was not found in the current directory.</value>
|
||||
<data name="ShutdownCommandFailed" xml:space="preserve">
|
||||
<value>The shutdown command failed: {0}</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
21
src/dotnet/BuildServer/MSBuildServer.cs
Normal file
21
src/dotnet/BuildServer/MSBuildServer.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.Build.Execution;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class MSBuildServer : IBuildServer
|
||||
{
|
||||
public int ProcessId => 0; // Not yet used
|
||||
|
||||
public string Name => LocalizableStrings.MSBuildServer;
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
BuildManager.DefaultBuildManager.ShutdownAllNodes();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +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.Threading.Tasks;
|
||||
using Microsoft.Build.Execution;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class MSBuildServerManager : IBuildServerManager
|
||||
{
|
||||
public string ServerName => LocalizableStrings.MSBuildServer;
|
||||
|
||||
public Task<Result> ShutdownServerAsync()
|
||||
{
|
||||
return Task.Run(() => {
|
||||
try
|
||||
{
|
||||
BuildManager.DefaultBuildManager.ShutdownAllNodes();
|
||||
return new Result(ResultKind.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +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.Cli.Utils;
|
||||
using Microsoft.Build.Execution;
|
||||
using Microsoft.Extensions.EnvironmentAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class RazorAssemblyResolver : IRazorAssemblyResolver
|
||||
{
|
||||
private readonly IDirectory _directory;
|
||||
|
||||
public RazorAssemblyResolver(IDirectory directory = null)
|
||||
{
|
||||
_directory = directory ?? FileSystemWrapper.Default.Directory;
|
||||
}
|
||||
|
||||
public IEnumerable<FilePath> EnumerateRazorToolAssemblies()
|
||||
{
|
||||
HashSet<string> seen = new HashSet<string>();
|
||||
|
||||
var globalProperties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
// This property disables default item globbing to improve performance
|
||||
// This should be safe because we are not evaluating items, only properties
|
||||
{ Constants.EnableDefaultItems, "false" }
|
||||
};
|
||||
|
||||
foreach (var projectFile in _directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.*proj"))
|
||||
{
|
||||
var project = new ProjectInstance(projectFile, globalProperties, null);
|
||||
var path = project.GetPropertyValue("_RazorToolAssembly");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!seen.Add(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new FilePath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
src/dotnet/BuildServer/RazorPidFile.cs
Normal file
65
src/dotnet/BuildServer/RazorPidFile.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
// 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.Text;
|
||||
using Microsoft.Extensions.EnvironmentAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class RazorPidFile
|
||||
{
|
||||
public const string RazorServerType = "rzc";
|
||||
public const string FilePrefix = "rzc-";
|
||||
|
||||
public RazorPidFile(FilePath path, int processId, FilePath serverPath, string pipeName)
|
||||
{
|
||||
Path = path;
|
||||
ProcessId = processId;
|
||||
ServerPath = serverPath;
|
||||
PipeName = pipeName ?? throw new ArgumentNullException(pipeName);
|
||||
}
|
||||
|
||||
public FilePath Path { get; }
|
||||
|
||||
public int ProcessId;
|
||||
|
||||
public FilePath ServerPath { get; }
|
||||
|
||||
public string PipeName { get; }
|
||||
|
||||
public static RazorPidFile Read(FilePath path, IFileSystem fileSystem = null)
|
||||
{
|
||||
fileSystem = fileSystem ?? FileSystemWrapper.Default;
|
||||
|
||||
using (var stream = fileSystem.File.OpenRead(path.Value))
|
||||
using (var reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
if (!int.TryParse(reader.ReadLine(), out var processId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (reader.ReadLine() != RazorServerType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var serverPath = reader.ReadLine();
|
||||
if (string.IsNullOrEmpty(serverPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pipeName = reader.ReadLine();
|
||||
if (string.IsNullOrEmpty(pipeName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new RazorPidFile(path, processId, new FilePath(serverPath), pipeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
src/dotnet/BuildServer/RazorServer.cs
Normal file
77
src/dotnet/BuildServer/RazorServer.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
// 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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Tools;
|
||||
using Microsoft.Extensions.EnvironmentAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class RazorServer : IBuildServer
|
||||
{
|
||||
private readonly ICommandFactory _commandFactory;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public RazorServer(
|
||||
RazorPidFile pidFile,
|
||||
ICommandFactory commandFactory = null,
|
||||
IFileSystem fileSystem = null)
|
||||
{
|
||||
PidFile = pidFile ?? throw new ArgumentNullException(nameof(pidFile));
|
||||
_commandFactory = commandFactory ?? new DotNetCommandFactory(alwaysRunOutOfProc: true);
|
||||
_fileSystem = fileSystem ?? FileSystemWrapper.Default;
|
||||
}
|
||||
|
||||
public int ProcessId => PidFile.ProcessId;
|
||||
|
||||
public string Name => LocalizableStrings.RazorServer;
|
||||
|
||||
public RazorPidFile PidFile { get; }
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
var command = _commandFactory
|
||||
.Create(
|
||||
"exec",
|
||||
new string[] {
|
||||
PidFile.ServerPath.Value,
|
||||
"shutdown",
|
||||
"-w", // Wait for exit
|
||||
"-p", // Pipe name
|
||||
PidFile.PipeName
|
||||
})
|
||||
.CaptureStdOut()
|
||||
.CaptureStdErr();
|
||||
|
||||
var result = command.Execute();
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
throw new BuildServerException(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutdownCommandFailed,
|
||||
result.StdErr));
|
||||
}
|
||||
|
||||
// After a successful shutdown, ensure the pid file is deleted
|
||||
// If the pid file was left behind due to a rude exit, this ensures we don't try to shut it down again
|
||||
try
|
||||
{
|
||||
if (_fileSystem.File.Exists(PidFile.Path.Value))
|
||||
{
|
||||
_fileSystem.File.Delete(PidFile.Path.Value);
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +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.Threading.Tasks;
|
||||
using Microsoft.Build.Exceptions;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.Tools;
|
||||
using Microsoft.Extensions.EnvironmentAbstractions;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class RazorServerManager : IBuildServerManager
|
||||
{
|
||||
private readonly IRazorAssemblyResolver _resolver;
|
||||
private readonly ICommandFactory _commandFactory;
|
||||
|
||||
public RazorServerManager(IRazorAssemblyResolver resolver = null, ICommandFactory commandFactory = null)
|
||||
{
|
||||
_resolver = resolver ?? new RazorAssemblyResolver();
|
||||
_commandFactory = commandFactory ?? new DotNetCommandFactory(alwaysRunOutOfProc: true);
|
||||
}
|
||||
|
||||
public string ServerName => LocalizableStrings.RazorServer;
|
||||
|
||||
public Task<Result> ShutdownServerAsync()
|
||||
{
|
||||
return Task.Run(() => {
|
||||
try
|
||||
{
|
||||
bool haveRazorAssembly = false;
|
||||
|
||||
foreach (var toolAssembly in _resolver.EnumerateRazorToolAssemblies())
|
||||
{
|
||||
haveRazorAssembly = true;
|
||||
|
||||
var command = _commandFactory
|
||||
.Create("exec", new string[] { toolAssembly.Value, "shutdown" })
|
||||
.CaptureStdOut()
|
||||
.CaptureStdErr();
|
||||
|
||||
var result = command.Execute();
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
return new Result(ResultKind.Failure, result.StdErr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveRazorAssembly)
|
||||
{
|
||||
return new Result(ResultKind.Skipped, LocalizableStrings.NoRazorProjectFound);
|
||||
}
|
||||
|
||||
return new Result(ResultKind.Success);
|
||||
}
|
||||
catch (InvalidProjectFileException ex)
|
||||
{
|
||||
return new Result(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +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;
|
||||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal enum ResultKind
|
||||
{
|
||||
Success,
|
||||
Failure,
|
||||
Skipped
|
||||
}
|
||||
|
||||
internal struct Result
|
||||
{
|
||||
public Result(ResultKind kind, string message = null)
|
||||
{
|
||||
Kind = kind;
|
||||
Message = message;
|
||||
Exception = null;
|
||||
}
|
||||
|
||||
public Result(Exception exception)
|
||||
{
|
||||
Kind = ResultKind.Failure;
|
||||
Message = exception.Message;
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
public ResultKind Kind { get; private set; }
|
||||
|
||||
public string Message { get; private set; }
|
||||
|
||||
public Exception Exception { get; private set; }
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ using Microsoft.DotNet.Cli.Utils;
|
|||
|
||||
namespace Microsoft.DotNet.BuildServer
|
||||
{
|
||||
internal class VBCSCompilerServerManager : IBuildServerManager
|
||||
internal class VBCSCompilerServer : IBuildServer
|
||||
{
|
||||
internal static readonly string VBCSCompilerPath = Path.Combine(
|
||||
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
|
||||
|
@ -20,29 +20,30 @@ namespace Microsoft.DotNet.BuildServer
|
|||
|
||||
private readonly ICommandFactory _commandFactory;
|
||||
|
||||
public VBCSCompilerServerManager(ICommandFactory commandFactory = null)
|
||||
public VBCSCompilerServer(ICommandFactory commandFactory = null)
|
||||
{
|
||||
_commandFactory = commandFactory ?? new DotNetCommandFactory(alwaysRunOutOfProc: true);
|
||||
}
|
||||
|
||||
public string ServerName => LocalizableStrings.VBCSCompilerServer;
|
||||
public int ProcessId => 0; // Not yet used
|
||||
|
||||
public Task<Result> ShutdownServerAsync()
|
||||
public string Name => LocalizableStrings.VBCSCompilerServer;
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
return Task.Run(() => {
|
||||
var command = _commandFactory
|
||||
.Create("exec", new[] { VBCSCompilerPath, "-shutdown" })
|
||||
.CaptureStdOut()
|
||||
.CaptureStdErr();
|
||||
var command = _commandFactory
|
||||
.Create("exec", new[] { VBCSCompilerPath, "-shutdown" })
|
||||
.CaptureStdOut()
|
||||
.CaptureStdErr();
|
||||
|
||||
var result = command.Execute();
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
return new Result(ResultKind.Failure, result.StdErr);
|
||||
}
|
||||
|
||||
return new Result(ResultKind.Success);
|
||||
});
|
||||
var result = command.Execute();
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
throw new BuildServerException(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutdownCommandFailed,
|
||||
result.StdErr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<target state="new">Razor build server</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoRazorProjectFound">
|
||||
<source>a Razor project was not found in the current directory.</source>
|
||||
<target state="new">a Razor project was not found in the current directory.</target>
|
||||
<trans-unit id="ShutdownCommandFailed">
|
||||
<source>The shutdown command failed: {0}</source>
|
||||
<target state="new">The shutdown command failed: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace Microsoft.DotNet.Tools.BuildServer.Shutdown
|
|||
{
|
||||
internal class BuildServerShutdownCommand : CommandBase
|
||||
{
|
||||
private readonly ServerEnumerationFlags _enumerationFlags;
|
||||
private readonly IBuildServerProvider _serverProvider;
|
||||
private readonly bool _useOrderedWait;
|
||||
private readonly IReporter _reporter;
|
||||
private readonly IReporter _errorReporter;
|
||||
|
@ -21,57 +23,63 @@ namespace Microsoft.DotNet.Tools.BuildServer.Shutdown
|
|||
public BuildServerShutdownCommand(
|
||||
AppliedOption options,
|
||||
ParseResult result,
|
||||
IEnumerable<IBuildServerManager> managers = null,
|
||||
IBuildServerProvider serverProvider = null,
|
||||
bool useOrderedWait = false,
|
||||
IReporter reporter = null)
|
||||
: base(result)
|
||||
{
|
||||
if (managers == null)
|
||||
bool msbuild = options.ValueOrDefault<bool>("msbuild");
|
||||
bool vbcscompiler = options.ValueOrDefault<bool>("vbcscompiler");
|
||||
bool razor = options.ValueOrDefault<bool>("razor");
|
||||
bool all = !msbuild && !vbcscompiler && !razor;
|
||||
|
||||
_enumerationFlags = ServerEnumerationFlags.None;
|
||||
if (msbuild || all)
|
||||
{
|
||||
bool msbuild = options.ValueOrDefault<bool>("msbuild");
|
||||
bool vbcscompiler = options.ValueOrDefault<bool>("vbcscompiler");
|
||||
bool razor = options.ValueOrDefault<bool>("razor");
|
||||
bool all = !msbuild && !vbcscompiler && !razor;
|
||||
|
||||
var enabledManagers = new List<IBuildServerManager>();
|
||||
if (msbuild || all)
|
||||
{
|
||||
enabledManagers.Add(new MSBuildServerManager());
|
||||
}
|
||||
|
||||
if (vbcscompiler || all)
|
||||
{
|
||||
enabledManagers.Add(new VBCSCompilerServerManager());
|
||||
}
|
||||
|
||||
if (razor || all)
|
||||
{
|
||||
enabledManagers.Add(new RazorServerManager());
|
||||
}
|
||||
|
||||
managers = enabledManagers;
|
||||
_enumerationFlags |= ServerEnumerationFlags.MSBuild;
|
||||
}
|
||||
|
||||
Managers = managers;
|
||||
if (vbcscompiler || all)
|
||||
{
|
||||
_enumerationFlags |= ServerEnumerationFlags.VBCSCompiler;
|
||||
}
|
||||
|
||||
if (razor || all)
|
||||
{
|
||||
_enumerationFlags |= ServerEnumerationFlags.Razor;
|
||||
}
|
||||
|
||||
_serverProvider = serverProvider ?? new BuildServerProvider();
|
||||
_useOrderedWait = useOrderedWait;
|
||||
_reporter = reporter ?? Reporter.Output;
|
||||
_errorReporter = reporter ?? Reporter.Error;
|
||||
}
|
||||
|
||||
public IEnumerable<IBuildServerManager> Managers { get; }
|
||||
|
||||
public override int Execute()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
var tasks = StartShutdown();
|
||||
|
||||
if (tasks.Count == 0)
|
||||
{
|
||||
_reporter.WriteLine(LocalizableStrings.NoServersToShutdown.Green());
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
while (tasks.Count > 0)
|
||||
{
|
||||
var index = WaitForResult(tasks.Select(t => t.Item2).ToArray());
|
||||
var (manager, task) = tasks[index];
|
||||
var (server, task) = tasks[index];
|
||||
|
||||
success &= HandleResult(manager, task.Result);
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
success = false;
|
||||
WriteFailureMessage(server, task.Exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteSuccessMessage(server);
|
||||
}
|
||||
|
||||
tasks.RemoveAt(index);
|
||||
}
|
||||
|
@ -79,14 +87,15 @@ namespace Microsoft.DotNet.Tools.BuildServer.Shutdown
|
|||
return success ? 0 : 1;
|
||||
}
|
||||
|
||||
private List<(IBuildServerManager, Task<Result>)> StartShutdown()
|
||||
private List<(IBuildServer, Task)> StartShutdown()
|
||||
{
|
||||
var tasks = new List<(IBuildServerManager, Task<Result>)>();
|
||||
foreach (var manager in Managers)
|
||||
var tasks = new List<(IBuildServer, Task)>();
|
||||
foreach (var server in _serverProvider.EnumerateBuildServers(_enumerationFlags))
|
||||
{
|
||||
_reporter.WriteLine(string.Format(LocalizableStrings.ShuttingDownServer, manager.ServerName));
|
||||
tasks.Add((manager, manager.ShutdownServerAsync()));
|
||||
WriteShutdownMessage(server);
|
||||
tasks.Add((server, Task.Run(() => server.Shutdown())));
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
|
@ -94,50 +103,72 @@ namespace Microsoft.DotNet.Tools.BuildServer.Shutdown
|
|||
{
|
||||
if (_useOrderedWait)
|
||||
{
|
||||
tasks[0].Wait();
|
||||
return 0;
|
||||
return Task.WaitAny(tasks.First());
|
||||
}
|
||||
return Task.WaitAny(tasks);
|
||||
}
|
||||
|
||||
private bool HandleResult(IBuildServerManager manager, Result result)
|
||||
private void WriteShutdownMessage(IBuildServer server)
|
||||
{
|
||||
switch (result.Kind)
|
||||
if (server.ProcessId != 0)
|
||||
{
|
||||
case ResultKind.Success:
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutDownSucceeded,
|
||||
manager.ServerName).Green());
|
||||
return true;
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShuttingDownServerWithPid,
|
||||
server.Name,
|
||||
server.ProcessId));
|
||||
}
|
||||
else
|
||||
{
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShuttingDownServer,
|
||||
server.Name));
|
||||
}
|
||||
}
|
||||
|
||||
case ResultKind.Skipped:
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutDownSkipped,
|
||||
manager.ServerName,
|
||||
result.Message).Cyan());
|
||||
return true;
|
||||
private void WriteFailureMessage(IBuildServer server, AggregateException exception)
|
||||
{
|
||||
if (server.ProcessId != 0)
|
||||
{
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutDownFailedWithPid,
|
||||
server.Name,
|
||||
server.ProcessId,
|
||||
exception.InnerException.Message).Red());
|
||||
}
|
||||
else
|
||||
{
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutDownFailed,
|
||||
server.Name,
|
||||
exception.InnerException.Message).Red());
|
||||
}
|
||||
|
||||
case ResultKind.Failure:
|
||||
_errorReporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutDownFailed,
|
||||
manager.ServerName,
|
||||
result.Message).Red());
|
||||
if (Reporter.IsVerbose)
|
||||
{
|
||||
Reporter.Verbose.WriteLine(exception.ToString().Red());
|
||||
}
|
||||
}
|
||||
|
||||
if (Reporter.IsVerbose && result.Exception != null)
|
||||
{
|
||||
Reporter.Verbose.WriteLine(result.Exception.ToString().Red());
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(
|
||||
string.Format(
|
||||
LocalizableStrings.UnsupportedEnumValue,
|
||||
result.Kind.ToString(),
|
||||
nameof(ResultKind)));
|
||||
private void WriteSuccessMessage(IBuildServer server)
|
||||
{
|
||||
if (server.ProcessId != 0)
|
||||
{
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutDownSucceededWithPid,
|
||||
server.Name,
|
||||
server.ProcessId).Green());
|
||||
}
|
||||
else
|
||||
{
|
||||
_reporter.WriteLine(
|
||||
string.Format(
|
||||
LocalizableStrings.ShutDownSucceeded,
|
||||
server.Name).Green());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,16 +132,22 @@
|
|||
<data name="ShuttingDownServer" xml:space="preserve">
|
||||
<value>Shutting down {0}...</value>
|
||||
</data>
|
||||
<data name="ShuttingDownServerWithPid" xml:space="preserve">
|
||||
<value>Shutting down {0} (process {1})...</value>
|
||||
</data>
|
||||
<data name="ShutDownSucceeded" xml:space="preserve">
|
||||
<value>{0} shut down successfully.</value>
|
||||
</data>
|
||||
<data name="ShutDownSucceededWithPid" xml:space="preserve">
|
||||
<value>{0} (process {1}) shut down successfully.</value>
|
||||
</data>
|
||||
<data name="ShutDownFailed" xml:space="preserve">
|
||||
<value>{0} failed to shut down: {1}</value>
|
||||
</data>
|
||||
<data name="ShutDownSkipped" xml:space="preserve">
|
||||
<value>{0} shut down was skipped: {1}</value>
|
||||
<data name="ShutDownFailedWithPid" xml:space="preserve">
|
||||
<value>{0} (process {1}) failed to shut down: {2}</value>
|
||||
</data>
|
||||
<data name="UnsupportedEnumValue" xml:space="preserve">
|
||||
<value>The value '{0}' for enum type '{1}' is not supported.</value>
|
||||
<data name="NoServersToShutdown" xml:space="preserve">
|
||||
<value>No build servers are running.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -37,14 +37,24 @@
|
|||
<target state="new">{0} failed to shut down: {1}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownSkipped">
|
||||
<source>{0} shut down was skipped: {1}</source>
|
||||
<target state="new">{0} shut down was skipped: {1}</target>
|
||||
<trans-unit id="ShuttingDownServerWithPid">
|
||||
<source>Shutting down {0} (process {1})...</source>
|
||||
<target state="new">Shutting down {0} (process {1})...</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="UnsupportedEnumValue">
|
||||
<source>The value '{0}' for enum type '{1}' is not supported.</source>
|
||||
<target state="new">The value '{0}' for enum type '{1}' is not supported.</target>
|
||||
<trans-unit id="ShutDownSucceededWithPid">
|
||||
<source>{0} (process {1}) shut down successfully.</source>
|
||||
<target state="new">{0} (process {1}) shut down successfully.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ShutDownFailedWithPid">
|
||||
<source>{0} (process {1}) failed to shut down: {2}</source>
|
||||
<target state="new">{0} (process {1}) failed to shut down: {2}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="NoServersToShutdown">
|
||||
<source>No build servers are running.</source>
|
||||
<target state="new">No build servers are running.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
</body>
|
||||
|
|
|
@ -166,7 +166,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)
|
||||
|
|
143
test/dotnet.Tests/BuildServerTests/BuildServerProviderTests.cs
Normal file
143
test/dotnet.Tests/BuildServerTests/BuildServerProviderTests.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
// 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.Extensions.DependencyModel.Tests;
|
||||
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);
|
||||
}
|
||||
|
||||
private Mock<IEnvironmentProvider> CreateEnvironmentProviderMock(string value = null)
|
||||
{
|
||||
var provider = new Mock<IEnvironmentProvider>(MockBehavior.Strict);
|
||||
|
||||
provider
|
||||
.Setup(p => p.GetEnvironmentVariable("DOTNET_BUILD_PIDFILE_DIRECTORY"))
|
||||
.Returns(value);
|
||||
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
109
test/dotnet.Tests/BuildServerTests/RazorServerTests.cs
Normal file
109
test/dotnet.Tests/BuildServerTests/RazorServerTests.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ 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;
|
||||
|
@ -26,57 +25,92 @@ namespace Microsoft.DotNet.Tests.Commands
|
|||
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 +128,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 +150,80 @@ 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()
|
||||
{
|
||||
const string FailureMessage = "failed!";
|
||||
const string SkipMessage = "skipped!";
|
||||
|
||||
var mocks = new[] {
|
||||
CreateManagerMock("first", new Result(ResultKind.Success)),
|
||||
CreateManagerMock("second", new Result(ResultKind.Failure, FailureMessage)),
|
||||
CreateManagerMock("third", new Result(ResultKind.Skipped, SkipMessage))
|
||||
};
|
||||
|
||||
var command = CreateCommand(managers: mocks.Select(m => m.Object));
|
||||
|
||||
command.Execute().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));
|
||||
|
||||
VerifyShutdownCalls(mocks);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue