Fix xunnit test for PS (#4780)

* Initial work to enable xunit

* Moved AssemblyOriginatorKeyFile to csharp.tests.csproj

* Native binary has dylib extension on macOS
This commit is contained in:
Chunqing Chen 2017-11-30 14:44:41 -08:00 committed by Aditya Patwardhan
parent 47f8467e49
commit 52df947080
15 changed files with 179 additions and 104 deletions

View File

@ -1188,6 +1188,53 @@ function Show-PSPesterError
}
function Test-XUnitTestResults
{
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $TestResultsFile
)
if(-not (Test-Path $TestResultsFile))
{
throw "File not found $TestResultsFile"
}
try
{
$results = [xml] (Get-Content $TestResultsFile)
}
catch
{
throw "Cannot convert $TestResultsFile to xml : $($_.message)"
}
$failedTests = $results.assemblies.assembly.collection | Where-Object failed -gt 0
if(-not $failedTests)
{
return $true
}
foreach($failure in $failedTests)
{
$description = $failure.test.type
$name = $failure.test.method
$message = $failure.test.failure.message.'#cdata-section'
$stackTrace = $failure.test.failure.'stack-trace'.'#cdata-section'
logerror ("Description: " + $description)
logerror ("Name: " + $name)
logerror "message:"
logerror $message
logerror "stack-trace:"
logerror $stackTrace
}
throw "$($failedTests.failed) tests failed"
}
#
# Read the test result file and
# Throw if a test failed
@ -1251,46 +1298,67 @@ function Test-PSPesterResults
function Start-PSxUnit {
[CmdletBinding()]param()
log "xUnit tests are currently disabled pending fixes due to API and AssemblyLoadContext changes - @andschwa"
return
if ($Environment.IsWindows) {
throw "xUnit tests are only currently supported on Linux / OS X"
}
if ($Environment.IsMacOS) {
log "Not yet supported on OS X, pretending they passed..."
return
}
[CmdletBinding()]param(
[string] $TestResultsFile = "XUnitResults.xml"
)
# Add .NET CLI tools to PATH
Find-Dotnet
$Arguments = "--configuration", "Linux", "-parallel", "none"
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
$Arguments += "-verbose"
}
$Content = Split-Path -Parent (Get-PSOutput)
if (-not (Test-Path $Content)) {
throw "PowerShell must be built before running tests!"
}
if(Test-Path $TestResultsFile)
{
Remove-Item $TestResultsFile -Force -ErrorAction SilentlyContinue
}
try {
Push-Location $PSScriptRoot/test/csharp
# Path manipulation to obtain test project output directory
$Output = Join-Path $pwd ((Split-Path -Parent (Get-PSOutput)) -replace (New-PSOptions).Top)
Write-Verbose "Output is $Output"
dotnet restore
Copy-Item -ErrorAction SilentlyContinue -Recurse -Path $Content/* -Include Modules,libpsl-native* -Destination $Output
Start-NativeExecution { dotnet test $Arguments }
if ($LASTEXITCODE -ne 0) {
throw "$LASTEXITCODE xUnit tests failed"
# --fx-version workaround required due to https://github.com/dotnet/cli/issues/7901#issuecomment-343323674
if($Environment.IsWindows)
{
dotnet xunit --fx-version 2.0.0 -xml $TestResultsFile
}
} finally {
else
{
if($Environment.IsMacOS)
{
$nativeLib = "$Content/libpsl-native.dylib"
}
else
{
$nativeLib = "$Content/libpsl-native.so"
}
$requiredDependencies = @(
$nativeLib,
"$Content/Microsoft.Management.Infrastructure.dll",
"$Content/System.Text.Encoding.CodePages.dll"
)
if((Test-Path $requiredDependencies) -notcontains $false)
{
$options = New-PSOptions
$Destination = "bin/$($options.configuration)/$($options.framework)"
New-Item $Destination -ItemType Directory -Force > $null
Copy-Item -Path $requiredDependencies -Destination $Destination -Force
}
else
{
throw "Dependencies $requiredDependencies not met."
}
dotnet xunit --fx-version 2.0.0 -configuration $Options.configuration -xml $TestResultsFile
}
}
finally {
Pop-Location
}
}

View File

@ -1,21 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Test.Common.props"/>
<Import Project="../Test.Common.props"/>
<PropertyGroup>
<Description>PowerShell On Linux xUnit Tests</Description>
<Description>PowerShell xUnit Tests</Description>
<AssemblyName>powershell-tests</AssemblyName>
<RuntimeIdentifiers>win7-x86;win7-x64;osx.10.12-x64;linux-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup>
<DelaySign>true</DelaySign>
<AssemblyOriginatorKeyFile>../../src/signing/visualstudiopublic.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\System.Management.Automation\System.Management.Automation.csproj" />
<ProjectReference Include="../../src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj"/>
<ProjectReference Include="../../src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj"/>
<ProjectReference Include="../../src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
<PackageReference Include="xunit" Version="2.3.0" />
<!-- DotNetCliToolReference element specifies the CLI tool that the user wants to restore in the context of the project. -->
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0" />
<PackageReference Include="Xunit.SkippableFact" Version="1.3.3" />
</ItemGroup>
</Project>

View File

@ -1,25 +0,0 @@
using Xunit;
using System;
using System.Management.Automation;
// This collection fixture initializes Core PowerShell's AssemblyLoadContext once and only
// once. Attempting to initialize in a class level fixture will cause multiple
// initializations, resulting in test failure due to "Binding model is already locked for
// the AppDomain and cannot be reset".
namespace PSTests
{
public class AssemblyLoadContextFixture
{
public AssemblyLoadContextFixture()
{
// Initialize the Core PowerShell AssemblyLoadContext
PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(AppContext.BaseDirectory);
}
}
[CollectionDefinition("AssemblyLoadContext")]
public class AssemblyLoadContextCollection : ICollectionFixture<AssemblyLoadContextFixture>
{
// nothing to do but satisfy the interface
}
}

View File

@ -4,14 +4,13 @@ using System.Management.Automation.Language;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public static class PSEnumerableBinderTests
{
[Fact]
public static void TestIsComObject()
public static void TestIsStaticTypePossiblyEnumerable()
{
// It just needs an arbitrary object
Assert.False(PSEnumerableBinder.IsComObject(42));
// It just needs an arbitrary type
Assert.False(PSEnumerableBinder.IsStaticTypePossiblyEnumerable(42.GetType()));
}
}
}

View File

@ -6,7 +6,6 @@ using System.Management.Automation;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public static class PlatformTests
{
[Fact]
@ -15,6 +14,7 @@ namespace PSTests
Assert.True(Platform.IsCoreCLR);
}
#if Unix
[Fact]
public static void TestGetUserName()
{
@ -38,7 +38,7 @@ namespace PSTests
}
}
[Fact(Skip="Bad arguments for macOS")]
[Fact]
public static void TestGetMachineName()
{
var startInfo = new ProcessStartInfo
@ -61,7 +61,7 @@ namespace PSTests
}
}
[Fact(Skip="Bad arguments for macOS")]
[Fact]
public static void TestGetFQDN()
{
var startInfo = new ProcessStartInfo
@ -84,7 +84,7 @@ namespace PSTests
}
}
[Fact(Skip="Bad arguments for macOS")]
[Fact]
public static void TestGetDomainName()
{
var startInfo = new ProcessStartInfo
@ -255,5 +255,6 @@ namespace PSTests
File.Delete(path);
File.Delete(link);
}
#endif
}
}

View File

@ -4,14 +4,12 @@ using System.Management.Automation;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public static class PSTypeExtensionsTests
{
[Fact]
public static void TestIsComObject()
public static void TestIsNumeric()
{
// It just needs an arbitrary type
Assert.False(PSTypeExtensions.IsComObject(42.GetType()));
Assert.True(PSTypeExtensions.IsNumeric(42.GetType()));
}
}
}

View File

@ -13,10 +13,10 @@ using System.Management.Automation.Provider;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;
using Microsoft.PowerShell.Commands;
using System.Reflection;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public class FileSystemProviderTests: IDisposable
{
private string testPath;
@ -57,7 +57,14 @@ namespace PSTests
[Fact]
public void TestCreateJunctionFails()
{
Assert.False(InternalSymbolicLinkLinkCodeMethods.CreateJunction("",""));
if(!Platform.IsWindows)
{
Assert.False(InternalSymbolicLinkLinkCodeMethods.CreateJunction("",""));
}
else
{
Assert.Throws<System.ArgumentNullException>(delegate { InternalSymbolicLinkLinkCodeMethods.CreateJunction("",""); });
}
}
[Fact]
@ -73,12 +80,26 @@ namespace PSTests
public void TestMode()
{
Assert.Equal(FileSystemProvider.Mode(null),String.Empty);
FileSystemInfo directoryObject = new DirectoryInfo(@"/");
FileSystemInfo fileObject = new FileInfo(@"/etc/hosts");
FileSystemInfo executableObject = new FileInfo(@"/bin/echo");
Assert.Equal(FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r","-"),"d-----");
Assert.Equal(FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r","-"),"------");
Assert.Equal(FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r","-"),"------");
FileSystemInfo directoryObject = null;
FileSystemInfo fileObject = null;
FileSystemInfo executableObject = null;
if(!Platform.IsWindows)
{
directoryObject = new DirectoryInfo(@"/");
fileObject = new FileInfo(@"/etc/hosts");
executableObject = new FileInfo(@"/bin/echo");
}
else
{
directoryObject = new DirectoryInfo(System.Environment.CurrentDirectory);
fileObject = new FileInfo(System.Reflection.Assembly.GetEntryAssembly().Location);
executableObject = new FileInfo(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
}
Assert.Equal("d-----", FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r","-"));
Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r","-").Replace("a","-"));
Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r","-").Replace("a","-"));
}
[Fact]
@ -98,7 +119,7 @@ namespace PSTests
{
if(property.Name == "IsReadOnly")
{
Assert.Equal(property.Value,false);
Assert.False((bool)property.Value);
}
}
}
@ -117,7 +138,7 @@ namespace PSTests
{
if(property.Name == "Name")
{
Assert.Equal(property.Value,"test");
Assert.Equal("test", property.Value);
}
}
}

View File

@ -5,22 +5,23 @@ using System.Management.Automation;
namespace PSTests
{
// Not static because a test requires non-const variables
[Collection("AssemblyLoadContext")]
public class MshSnapinInfoTests
{
// Test that it does not throw an exception
[Fact]
[SkippableFact]
public void TestReadRegistryInfo()
{
Skip.IfNot(Platform.IsWindows);
Version someVersion = null;
string someString = null;
PSSnapInReader.ReadRegistryInfo(out someVersion, out someString, out someString, out someString, out someString, out someVersion);
}
// PublicKeyToken is null on Linux
[Fact]
[SkippableFact]
public void TestReadCoreEngineSnapIn()
{
Skip.IfNot(Platform.IsWindows);
PSSnapInInfo pSSnapInInfo = PSSnapInReader.ReadCoreEngineSnapIn();
Assert.Contains("PublicKeyToken=31bf3856ad364e35", pSSnapInInfo.AssemblyName);
}

View File

@ -4,7 +4,6 @@ using System.Management.Automation;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public static class PSVersionInfoTests
{
[Fact]

View File

@ -8,11 +8,10 @@ namespace PSTests
// NOTE: do not call AddCommand("out-host") after invoking or MergeMyResults,
// otherwise Invoke will not return any objects
[Collection("AssemblyLoadContext")]
public class RunspaceTests
{
private static int count = 3;
private static string script = String.Format($"get-command | select-object -first {count}");
private static int count = 1;
private static string script = String.Format($"get-command get-command");
[Fact]
public void TestRunspaceWithPipeline()
@ -63,7 +62,7 @@ namespace PSTests
}
[Fact(Skip="Fails in Travis CI, need investigation")]
[Fact]
public void TestRunspaceWithPowerShellAndInitialSessionState()
{
InitialSessionState iss = InitialSessionState.CreateDefault2();
@ -76,11 +75,14 @@ namespace PSTests
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.Runspace = runspace;
powerShell.AddScript("Import-Module Microsoft.PowerShell.Utility -Force");
powerShell.AddScript(script);
int objCount = 0;
foreach (var result in powerShell.Invoke())
var results = powerShell.Invoke();
foreach (var result in results)
{
// this is how an object would be captured here and looked at,
// each result is a PSObject with the data from the pipeline

View File

@ -4,21 +4,12 @@ using System.Management.Automation;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public static class SecuritySupportTests
{
[Fact]
public static void TestScanContent()
{
Assert.Equal(AmsiUtils.ScanContent("", ""), AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED);
}
[Fact]
public static void TestCurrentDomain_ProcessExit()
{
Assert.Throws<PlatformNotSupportedException>(delegate {
AmsiUtils.CurrentDomain_ProcessExit(null, EventArgs.Empty);
});
Assert.Equal(AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED, AmsiUtils.ScanContent("", ""));
}
[Fact]

View File

@ -12,12 +12,12 @@ using Microsoft.PowerShell;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public class SessionStateTests
{
[Fact]
[SkippableFact]
public void TestDrives()
{
Skip.IfNot(Platform.IsWindows);
CultureInfo currentCulture = CultureInfo.CurrentCulture;
PSHost hostInterface = new DefaultHost(currentCulture,currentCulture);
InitialSessionState iss = InitialSessionState.CreateDefault2();

View File

@ -1,15 +1,16 @@
using Xunit;
using System;
using System.Management.Automation;
using System.Reflection;
namespace PSTests
{
[Collection("AssemblyLoadContext")]
public static class UtilsTests
{
[Fact]
[SkippableFact]
public static void TestIsWinPEHost()
{
Skip.IfNot(Platform.IsWindows);
Assert.False(Utils.IsWinPEHost());
}
}

View File

@ -325,6 +325,7 @@ function Invoke-AppVeyorTest
Write-Host -Foreground Green 'Run CoreCLR tests'
$testResultsNonAdminFile = "$pwd\TestsResultsNonAdmin.xml"
$testResultsAdminFile = "$pwd\TestsResultsAdmin.xml"
$testResultsXUnitFile = "$pwd\TestResultsXUnit.xml"
if(!(Test-Path "$env:CoreOutput\pwsh.exe"))
{
throw "CoreCLR pwsh.exe was not built"
@ -358,6 +359,10 @@ function Invoke-AppVeyorTest
Write-Host -Foreground Green 'Upload CoreCLR Admin test results'
Update-AppVeyorTestResults -resultsFile $testResultsAdminFile
Start-PSxUnit -TestResultsFile $testResultsXUnitFile
Write-Host -ForegroundColor Green 'Uploading PSxUnit test results'
Update-AppVeyorTestResults -resultsFile $testResultsXUnitFile
#
# Fail the build, if tests failed
@(
@ -367,6 +372,8 @@ function Invoke-AppVeyorTest
Test-PSPesterResults -TestResultsFile $_
}
$testPassResult = Test-XUnitTestResults -TestResultsFile $testResultsXUnitFile
Set-BuildVariable -Name TestPassed -Value True
}

View File

@ -240,7 +240,10 @@ elseif($Stage -eq 'Build')
}
try {
Start-PSxUnit
$testResultsXUnitFile = "$pwd/TestResultsXUnit.xml"
Start-PSxUnit -TestResultsFile $testResultsXUnitFile
# If there are failures, Test-XUnitTestResults throws
$testPassResult = Test-XUnitTestResults -TestResultsFile $testResultsXUnitFile
}
catch {
$result = "FAIL"