dotnet-installer/test/Microsoft.DotNet.ShellShim.Tests/ShellShimMakerTests.cs
Peter Huene d8d600d44e
Merge branch 'release/2.1.3xx' into master
* release/2.1.3xx:
  Updating the WebSdk DependencyVersion to support local build
  Fix non-fatal null exception when no extra parameters are passed.
  Separate tool package and shim file location
  Updating the CLI branding and version to 2.1.300.

* Conflicts
  src/dotnet/commands/dotnet-install/dotnet-install-tool/InstallToolCommand.cs
  run-build.ps1
  build/Version.props
2018-01-30 16:47:05 -08:00

218 lines
8 KiB
C#

// 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.Linq;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using FluentAssertions;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.TestFramework;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.DotNet.Tools.Test.Utilities.Mock;
using Microsoft.DotNet.Tools.Tests.ComponentMocks;
using Microsoft.Extensions.EnvironmentAbstractions;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.DotNet.ShellShim.Tests
{
public class ShellShimMakerTests : TestBase
{
private readonly ITestOutputHelper _output;
public ShellShimMakerTests(ITestOutputHelper output)
{
_output = output;
}
[Theory]
[InlineData("my_native_app.exe", null)]
[InlineData("./my_native_app.js", "nodejs")]
[InlineData(@"C:\tools\my_native_app.dll", "dotnet")]
public void GivenAnRunnerOrEntryPointItCanCreateConfig(string entryPointPath, string runner)
{
var entryPoint = new FilePath(entryPointPath);
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return;
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
var tmpFile = Path.Combine(TempRoot.Root, Path.GetRandomFileName());
shellShimMaker.CreateConfigFile(tmpFile, entryPoint, runner);
new FileInfo(tmpFile).Should().Exist();
var generated = XDocument.Load(tmpFile);
generated.Descendants("appSettings")
.Descendants("add")
.Should()
.Contain(e => e.Attribute("key").Value == "runner" && e.Attribute("value").Value == (runner ?? string.Empty))
.And
.Contain(e => e.Attribute("key").Value == "entryPoint" && e.Attribute("value").Value == entryPoint.Value);
}
[Fact]
public void GivenAnExecutablePathItCanGenerateShimFile()
{
var outputDll = MakeHelloWorldExecutableDll();
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
shellShimMaker.CreateShim(
new FilePath(outputDll.FullName),
shellCommandName);
var stdOut = ExecuteInShell(shellCommandName);
stdOut.Should().Contain("Hello World");
}
[Fact]
public void GivenAnExecutablePathDirectoryThatDoesNotExistItCanGenerateShimFile()
{
var outputDll = MakeHelloWorldExecutableDll();
var extraNonExistDirectory = Path.GetRandomFileName();
var shellShimMaker = new ShellShimMaker(Path.Combine(TempRoot.Root, extraNonExistDirectory));
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
Action a = () => shellShimMaker.CreateShim(
new FilePath(outputDll.FullName),
shellCommandName);
a.ShouldNotThrow<DirectoryNotFoundException>();
}
[Theory]
[InlineData("arg1 arg2", new[] { "arg1", "arg2" })]
[InlineData(" \"arg1 with space\" arg2", new[] { "arg1 with space", "arg2" })]
[InlineData(" \"arg with ' quote\" ", new[] { "arg with ' quote" })]
public void GivenAShimItPassesThroughArguments(string arguments, string[] expectedPassThru)
{
var outputDll = MakeHelloWorldExecutableDll();
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
shellShimMaker.CreateShim(
new FilePath(outputDll.FullName),
shellCommandName);
var stdOut = ExecuteInShell(shellCommandName, arguments);
for (int i = 0; i < expectedPassThru.Length; i++)
{
stdOut.Should().Contain($"{i} = {expectedPassThru[i]}");
}
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void GivenAnExecutablePathWithExistingSameNameShimItThrows(bool testMockBehaviorIsInSync)
{
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
MakeNameConflictingCommand(TempRoot.Root, shellCommandName);
IShellShimMaker shellShimMaker;
if (testMockBehaviorIsInSync)
{
shellShimMaker = new ShellShimMakerMock(TempRoot.Root);
}
else
{
shellShimMaker = new ShellShimMaker(TempRoot.Root);
}
Action a = () => shellShimMaker.EnsureCommandNameUniqueness(shellCommandName);
a.ShouldThrow<GracefulException>()
.And.Message
.Should().Contain(
$"Failed to install tool {shellCommandName}. A command with the same name already exists.");
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void GivenAnExecutablePathWithoutExistingSameNameShimItShouldNotThrow(bool testMockBehaviorIsInSync)
{
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
IShellShimMaker shellShimMaker;
if (testMockBehaviorIsInSync)
{
shellShimMaker = new ShellShimMakerMock(TempRoot.Root);
}
else
{
shellShimMaker = new ShellShimMaker(TempRoot.Root);
}
Action a = () => shellShimMaker.EnsureCommandNameUniqueness(shellCommandName);
a.ShouldNotThrow();
}
private static void MakeNameConflictingCommand(string pathToPlaceShim, string shellCommandName)
{
File.WriteAllText(Path.Combine(pathToPlaceShim, shellCommandName), string.Empty);
}
private string ExecuteInShell(string shellCommandName, string arguments = "")
{
ProcessStartInfo processStartInfo;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var file = Path.Combine(TempRoot.Root, shellCommandName + ".exe");
processStartInfo = new ProcessStartInfo
{
FileName = file,
UseShellExecute = false,
Arguments = arguments,
};
}
else
{
processStartInfo = new ProcessStartInfo
{
FileName = "sh",
Arguments = shellCommandName + " " + arguments,
UseShellExecute = false
};
}
_output.WriteLine($"Launching '{processStartInfo.FileName} {processStartInfo.Arguments}'");
processStartInfo.WorkingDirectory = TempRoot.Root;
processStartInfo.EnvironmentVariables["PATH"] = Path.GetDirectoryName(new Muxer().MuxerPath);
processStartInfo.ExecuteAndCaptureOutput(out var stdOut, out var stdErr);
stdErr.Should().BeEmpty();
return stdOut ?? "";
}
private static FileInfo MakeHelloWorldExecutableDll()
{
const string testAppName = "TestAppSimple";
const string emptySpaceToTestSpaceInPath = " ";
TestAssetInstance testInstance = TestAssets.Get(testAppName)
.CreateInstance(testAppName + emptySpaceToTestSpaceInPath + "test")
.UseCurrentRuntimeFrameworkVersion()
.WithRestoreFiles()
.WithBuildFiles();
var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? "Debug";
FileInfo outputDll = testInstance.Root.GetDirectory("bin", configuration)
.GetDirectories().Single()
.GetFile($"{testAppName}.dll");
return outputDll;
}
}
}