Consolidated the two test exes into one (#3982)

Combined the previous echoargs and createchildprocess test exes into a single TestExe that can be extended for other tests.
This commit is contained in:
Steve Lee 2017-06-13 17:49:56 -07:00 committed by Jason Shirk
parent 65f96e0298
commit ea0082ab8d
9 changed files with 188 additions and 203 deletions

View file

@ -696,25 +696,31 @@ function Publish-PSTestTools {
Find-Dotnet
$tools = @("$PSScriptRoot/test/tools/EchoArgs", "echoargs"), @("$PSScriptRoot/test/tools/CreateChildProcess", "createchildprocess")
$tools = @(
@{Path="${PSScriptRoot}/test/tools/TestExe";Output="testexe"}
)
if ($Options -eq $null)
{
$Options = New-PSOptions
}
# Publish EchoArgs so it can be run by tests
# Publish tools so it can be run by tests
foreach ($tool in $tools)
{
Push-Location $tool[0]
Push-Location $tool.Path
try {
dotnet publish --output bin --configuration $Options.Configuration --framework $Options.Framework --runtime $Options.Runtime
$toolPath = Join-Path -Path $tool.Path -ChildPath "bin"
# add 'x' permission when building the standalone application
# this is temporary workaround to a bug in dotnet.exe, tracking by dotnet/cli issue #6286
if ($Options.Configuration -eq "Linux") {
$executable = Join-Path -Path $tool[0] -ChildPath "bin/$($tool[1])"
$executable = Join-Path -Path $toolPath -ChildPath "$($tool.Output)"
chmod u+x $executable
}
if ( $env:PATH -notcontains $toolPath ) {
$env:PATH = $toolPath+$TestModulePathSeparator+$($env:PATH)
}
} finally {
Pop-Location
}

View file

@ -1,41 +1,34 @@
Describe "Native Command Arguments" -tags "CI" {
# Find where test/powershell is so we can find the echoargs command relative to it
$powershellTestDir = $PSScriptRoot
while ($powershellTestDir -notmatch 'test[\\/]powershell$') {
$powershellTestDir = Split-Path $powershellTestDir
}
$echoArgs = Join-Path (Split-Path $powershellTestDir) tools/EchoArgs/bin/echoargs
# When passing arguments to native commands, quoted segments that contain
# spaces need to be quoted with '"' characters when they are passed to the
# native command (or to bash or sh on Linux).
#
# This test checks that the proper quoting is occuring by passing arguments
# to the echoargs native command and looking at how it got the arguments.
It "Should handle quoted spaces correctly" {
$a = 'a"b c"d'
$lines = & $echoArgs $a 'a"b c"d' a"b c"d
($lines | measure).Count | Should Be 3
$lines[0] | Should Be 'Arg 0 is <ab cd>'
$lines[1] | Should Be 'Arg 1 is <ab cd>'
$lines[2] | Should Be 'Arg 2 is <ab cd>'
}
# In order to pass '"' characters so they are actually part of command line
# arguments for native commands, they need to be escaped with a '\' (this
# is in addition to the '`' escaping needed inside '"' quoted strings in
# PowerShell).
#
# This functionality was broken in PowerShell 5.0 and 5.1, so this test
# will fail on those versions unless the fix is backported to them.
#
# This test checks that the proper quoting and escaping is occurring by
# passing arguments with escaped quotes to the echoargs native command and
# looking at how it got the arguments.
It "Should handle spaces between escaped quotes" {
$lines = & $echoArgs 'a\"b c\"d' "a\`"b c\`"d"
($lines | measure).Count | Should Be 2
$lines[0] | Should Be 'Arg 0 is <a"b c"d>'
$lines[1] | Should Be 'Arg 1 is <a"b c"d>'
}
}
Describe "Native Command Arguments" -tags "CI" {
# When passing arguments to native commands, quoted segments that contain
# spaces need to be quoted with '"' characters when they are passed to the
# native command (or to bash or sh on Linux).
#
# This test checks that the proper quoting is occuring by passing arguments
# to the testexe native command and looking at how it got the arguments.
It "Should handle quoted spaces correctly" {
$a = 'a"b c"d'
$lines = testexe -echoargs $a 'a"b c"d' a"b c"d
($lines | measure).Count | Should Be 3
$lines[0] | Should Be 'Arg 0 is <ab cd>'
$lines[1] | Should Be 'Arg 1 is <ab cd>'
$lines[2] | Should Be 'Arg 2 is <ab cd>'
}
# In order to pass '"' characters so they are actually part of command line
# arguments for native commands, they need to be escaped with a '\' (this
# is in addition to the '`' escaping needed inside '"' quoted strings in
# PowerShell).
#
# This functionality was broken in PowerShell 5.0 and 5.1, so this test
# will fail on those versions unless the fix is backported to them.
#
# This test checks that the proper quoting and escaping is occurring by
# passing arguments with escaped quotes to the testexe native command and
# looking at how it got the arguments.
It "Should handle spaces between escaped quotes" {
$lines = testexe -echoargs 'a\"b c\"d' "a\`"b c\`"d"
($lines | measure).Count | Should Be 2
$lines[0] | Should Be 'Arg 0 is <a"b c"d>'
$lines[1] | Should Be 'Arg 1 is <a"b c"d>'
}
}

View file

@ -27,35 +27,25 @@ Describe 'native commands lifecycle' -tags 'Feature' {
Describe "Native Command Processor" -tags "Feature" {
BeforeAll {
# Find where test/powershell is so we can find the createchildprocess command relative to it
$powershellTestDir = $PSScriptRoot
while ($powershellTestDir -notmatch 'test[\\/]powershell$') {
$powershellTestDir = Split-Path $powershellTestDir
}
$createchildprocess = Join-Path (Split-Path $powershellTestDir) tools/CreateChildProcess/bin/createchildprocess
}
# If powershell receives a StopProcessing, it should kill the native process and all child processes
# this test should pass and no longer Pending when #2561 is fixed
It "Should kill native process tree" -Pending {
# make sure no test processes are running
# on Linux, the Process class truncates the name so filter using Where-Object
Get-Process | Where-Object {$_.Name -like 'createchildproc*'} | Stop-Process
Get-Process testexe -ErrorAction SilentlyContinue | Stop-Process
[int] $numToCreate = 2
$ps = [PowerShell]::Create().AddCommand($createchildprocess)
$ps.AddParameter($numToCreate)
$ps = [PowerShell]::Create().AddCommand("testexe")
$ps.AddArgument("-createchildprocess")
$ps.AddArgument($numToCreate)
$async = $ps.BeginInvoke()
$ps.InvocationStateInfo.State | Should Be "Running"
[bool] $childrenCreated = $false
while (-not $childrenCreated)
{
$childprocesses = Get-Process | Where-Object {$_.Name -like 'createchildproc*'}
$childprocesses = Get-Process testexe -ErrorAction SilentlyContinue
if ($childprocesses.count -eq $numToCreate+1)
{
$childrenCreated = $true
@ -72,7 +62,7 @@ Describe "Native Command Processor" -tags "Feature" {
break
}
}
$childprocesses = Get-Process | Where-Object {$_.Name -like 'createchildproc*'}
$childprocesses = Get-Process testexe
$count = $childprocesses.count
$childprocesses | Stop-Process
$count | Should Be 0

View file

@ -1,70 +1,63 @@
Describe "Native streams behavior with PowerShell" -Tags 'CI' {
$powershell = Join-Path -Path $PsHome -ChildPath "powershell"
Context "Error stream" {
# we are using powershell itself as an example of a native program.
# we can create a behavior we want on the fly and test complex scenarios.
$error.Clear()
$command = [string]::Join('', @(
'[Console]::Error.Write(\"foo`n`nbar`n`nbaz\"); ',
'[Console]::Error.Write(\"middle\"); ',
'[Console]::Error.Write(\"foo`n`nbar`n`nbaz\")'
))
$out = & $powershell -noprofile -command $command 2>&1
# this check should be the first one, because $error is a global shared variable
It 'should not add records to $error variable' {
# we are keeping existing Windows PS v5.1 behavior for $error variable
$error.Count | Should Be 9
}
It 'uses ErrorRecord object to return stderr output' {
($out | measure).Count | Should BeGreaterThan 1
$out[0] | Should BeOfType 'System.Management.Automation.ErrorRecord'
$out[0].FullyQualifiedErrorId | Should Be 'NativeCommandError'
$out | Select-Object -Skip 1 | % {
$_ | Should BeOfType 'System.Management.Automation.ErrorRecord'
$_.FullyQualifiedErrorId | Should Be 'NativeCommandErrorMessage'
}
}
It 'uses correct exception messages for error stream' {
($out | measure).Count | Should Be 9
$out[0].Exception.Message | Should Be 'foo'
$out[1].Exception.Message | Should Be ''
$out[2].Exception.Message | Should Be 'bar'
$out[3].Exception.Message | Should Be ''
$out[4].Exception.Message | Should Be 'bazmiddlefoo'
$out[5].Exception.Message | Should Be ''
$out[6].Exception.Message | Should Be 'bar'
$out[7].Exception.Message | Should Be ''
$out[8].Exception.Message | Should Be 'baz'
}
It 'preserves error stream as is with Out-String' {
($out | Out-String).Replace("`r", '') | Should Be "foo`n`nbar`n`nbazmiddlefoo`n`nbar`n`nbaz`n"
}
}
}
Describe 'piping powershell objects to finished native executable' -Tags 'CI' {
# Find where test/powershell is so we can find the echoargs command relative to it
$powershellTestDir = $PSScriptRoot
while ($powershellTestDir -notmatch 'test[\\/]powershell$') {
$powershellTestDir = Split-Path $powershellTestDir
}
$echoArgs = Join-Path (Split-Path $powershellTestDir) tools/EchoArgs/bin/echoargs
It 'doesn''t throw any exceptions, when we are piping to the closed executable' {
1..3 | % {
Start-Sleep -Milliseconds 100
# yeild some multi-line formatted object
@{'a' = 'b'}
} | & $echoArgs | Should Be $null
}
}
Describe "Native streams behavior with PowerShell" -Tags 'CI' {
$powershell = Join-Path -Path $PsHome -ChildPath "powershell"
Context "Error stream" {
# we are using powershell itself as an example of a native program.
# we can create a behavior we want on the fly and test complex scenarios.
$error.Clear()
$command = [string]::Join('', @(
'[Console]::Error.Write(\"foo`n`nbar`n`nbaz\"); ',
'[Console]::Error.Write(\"middle\"); ',
'[Console]::Error.Write(\"foo`n`nbar`n`nbaz\")'
))
$out = & $powershell -noprofile -command $command 2>&1
# this check should be the first one, because $error is a global shared variable
It 'should not add records to $error variable' {
# we are keeping existing Windows PS v5.1 behavior for $error variable
$error.Count | Should Be 9
}
It 'uses ErrorRecord object to return stderr output' {
($out | measure).Count | Should BeGreaterThan 1
$out[0] | Should BeOfType 'System.Management.Automation.ErrorRecord'
$out[0].FullyQualifiedErrorId | Should Be 'NativeCommandError'
$out | Select-Object -Skip 1 | % {
$_ | Should BeOfType 'System.Management.Automation.ErrorRecord'
$_.FullyQualifiedErrorId | Should Be 'NativeCommandErrorMessage'
}
}
It 'uses correct exception messages for error stream' {
($out | measure).Count | Should Be 9
$out[0].Exception.Message | Should Be 'foo'
$out[1].Exception.Message | Should Be ''
$out[2].Exception.Message | Should Be 'bar'
$out[3].Exception.Message | Should Be ''
$out[4].Exception.Message | Should Be 'bazmiddlefoo'
$out[5].Exception.Message | Should Be ''
$out[6].Exception.Message | Should Be 'bar'
$out[7].Exception.Message | Should Be ''
$out[8].Exception.Message | Should Be 'baz'
}
It 'preserves error stream as is with Out-String' {
($out | Out-String).Replace("`r", '') | Should Be "foo`n`nbar`n`nbazmiddlefoo`n`nbar`n`nbaz`n"
}
}
}
Describe 'piping powershell objects to finished native executable' -Tags 'CI' {
It 'doesn''t throw any exceptions, when we are piping to the closed executable' {
1..3 | % {
Start-Sleep -Milliseconds 100
# yeild some multi-line formatted object
@{'a' = 'b'}
} | testexe -echoargs | Should Be $null
}
}

View file

@ -1,25 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading;
namespace CreateChildProcess
{
class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
uint num = UInt32.Parse(args[0]);
for (uint i = 0; i < num; i++)
{
Process child = new Process();
child.StartInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
child.Start();
}
}
// sleep is needed so the process doesn't exit before the test case kill it
Thread.Sleep(100000);
}
}
}

View file

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Very simple little console app that creates child processes of itself</Description>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>createchildprocess</AssemblyName>
<OutputType>Exe</OutputType>
<RuntimeIdentifiers>ubuntu.16.04-x64;ubuntu.14.04-x64;debian.8-x64;centos.7-x64;fedora.24-x64;win7-x86;win7-x64;win81-x64;win10-x64;osx.10.11-x64;osx.10.12-x64;opensuse.13.2-x64;opensuse.42.1-x64</RuntimeIdentifiers>
</PropertyGroup>
</Project>

View file

@ -1,25 +0,0 @@
//---------------------------------------------------------------------
// Author: Keith Hill
// Source: https://github.com/Pscx/Pscx/blob/master/Src/EchoArgs/EchoArgs.cs
//
// Description: Very simple little console class that you can use to see
// how PowerShell is passing parameters to legacy console
// apps.
//
// Creation Date: March 06, 2006
//---------------------------------------------------------------------
using System;
namespace Pscx.Applications
{
class EchoArgs
{
static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++)
{
Console.WriteLine("Arg {0} is <{1}>", i, args[i]);
}
}
}
}

View file

@ -0,0 +1,64 @@
using System;
using System.Threading;
using System.Diagnostics;
namespace TestExe
{
class TestExe
{
static void Main(string[] args)
{
if (args.Length > 0)
{
switch(args[0].ToLowerInvariant())
{
case "-echoargs":
EchoArgs(args);
break;
case "-createchildprocess":
CreateChildProcess(args);
break;
default:
Console.WriteLine("Unknown test {0}", args[0]);
break;
}
}
else
{
Console.WriteLine("Test not specified");
}
}
// <Summary>
// Echos back to stdout the arguments passed in
// </Summary>
static void EchoArgs(string[] args)
{
for (int i = 1; i < args.Length; i++)
{
Console.WriteLine("Arg {0} is <{1}>", i-1, args[i]);
}
}
// <Summary>
// First argument is the number of child processes to create which are instances of itself
// Processes automatically exit after 100 seconds
// </Summary>
static void CreateChildProcess(string[] args)
{
if (args.Length > 1)
{
uint num = UInt32.Parse(args[1]);
for (uint i = 0; i < num; i++)
{
Process child = new Process();
child.StartInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
child.StartInfo.Arguments = "-createchildprocess";
child.Start();
}
}
// sleep is needed so the process doesn't exit before the test case kill it
Thread.Sleep(100000);
}
}
}

View file

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Very simple little console class that you can use to see how PowerShell is passing parameters to legacy console apps.</Description>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>echoargs</AssemblyName>
<OutputType>Exe</OutputType>
<RuntimeIdentifiers>ubuntu.16.04-x64;ubuntu.14.04-x64;debian.8-x64;centos.7-x64;fedora.24-x64;win7-x86;win7-x64;win81-x64;win10-x64;osx.10.11-x64;osx.10.12-x64;opensuse.13.2-x64;opensuse.42.1-x64</RuntimeIdentifiers>
</PropertyGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Very simple little console class that you can use to for testing PowerShell interaction with native commands</Description>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>testexe</AssemblyName>
<OutputType>Exe</OutputType>
<RuntimeIdentifiers>ubuntu.16.04-x64;ubuntu.14.04-x64;debian.8-x64;centos.7-x64;fedora.24-x64;win7-x86;win7-x64;win81-x64;win10-x64;osx.10.11-x64;osx.10.12-x64;opensuse.13.2-x64;opensuse.42.1-x64</RuntimeIdentifiers>
</PropertyGroup>
</Project>