Merge pull request #9099 from peterhuene/razor-server-discovery
Implement Razor server discovery by pid file.
This commit is contained in:
commit
e1b5272540
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
Reference in a new issue