Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6cb0faa
[feature] fix enter-pshostprocess tests
TylerLeonhardt Feb 28, 2019
63fba3c
get more info
TylerLeonhardt Feb 28, 2019
f7de624
write the errors
TylerLeonhardt Feb 28, 2019
e6e9259
remote into this machine
TylerLeonhardt Feb 28, 2019
a710574
possible fix?
TylerLeonhardt Mar 1, 2019
9a491bc
check platform for better logs on *nix
TylerLeonhardt Mar 1, 2019
36a0741
sleeps
TylerLeonhardt Mar 1, 2019
77f80c3
wip: switch to jobs
TylerLeonhardt Mar 1, 2019
93d2a2b
switch to all jobs
TylerLeonhardt Mar 1, 2019
ab37807
add a couple comments
TylerLeonhardt Mar 1, 2019
b906140
add/move tests to ConsoleHost tests
TylerLeonhardt Mar 1, 2019
1f16388
different approach since start up isn't guessable
TylerLeonhardt Mar 1, 2019
167875c
using a retry
TylerLeonhardt Mar 1, 2019
85829b5
add a warning when it fails
TylerLeonhardt Mar 1, 2019
087ac08
add a comment for the helper function
TylerLeonhardt Mar 1, 2019
589575b
rename helper function
TylerLeonhardt Mar 1, 2019
d06c4f1
delete semicolon
TylerLeonhardt Mar 1, 2019
a02ae9d
address Ilya's comments
TylerLeonhardt Mar 3, 2019
2f1f030
typo
TylerLeonhardt Mar 3, 2019
0b1e797
change 0 to 1
iSazonov Mar 4, 2019
af77dff
address all feedback
TylerLeonhardt Mar 7, 2019
b5f298b
Merge branch 'fix-enter-pshostprocess-tests' of github.com:TylerLeonh…
TylerLeonhardt Mar 7, 2019
3e8f707
address aditya's feedback
TylerLeonhardt Mar 7, 2019
009a76b
fixed two urls
TylerLeonhardt Mar 7, 2019
bc12333
Merge branch 'fix-enter-pshostprocess-tests' of github.com:TylerLeonh…
TylerLeonhardt Mar 7, 2019
c9a3438
Merge branch 'master' into fix-enter-pshostprocess-tests
TylerLeonhardt Mar 7, 2019
de0b604
[feature] for CI
TylerLeonhardt Mar 8, 2019
54b8409
Merge branch 'fix-enter-pshostprocess-tests' of github.com:TylerLeonh…
TylerLeonhardt Mar 8, 2019
d7c0d1c
[feature] for CI
TylerLeonhardt Mar 8, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/learning-powershell/create-powershell-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ else
$IP | Where-Object {$_ -ne '127.0.0.1'}
```

[run-ps]:https://windowsitpro.com/powershell/running-powershell-scripts-easy-1-2-3
[run-ps]:https://www.itprotoday.com/powershell/running-powershell-scripts-easy-1-2-3
2 changes: 1 addition & 1 deletion docs/learning-powershell/powershell-beginners-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ For more details, see [Create and Run PowerShell Script Guide][create-run-script
[create-ps-module]:https://www.business.com/articles/powershell-modules/
[remoting]:https://channel9.msdn.com/Series/GetStartedPowerShell3/06
[in-depth]: https://channel9.msdn.com/events/MMS/2012/SV-B406
[remote-mgmt]:https://windowsitpro.com/powershell/powershell-basics-remote-management
[remote-mgmt]:https://www.itprotoday.com/powershell/powershell-basics-remote-management
[remote-commands]:https://docs.microsoft.com/powershell/scripting/core-powershell/running-remote-commands?view=powershell-6
[examples]:https://examples.oreilly.com/9780596528492/
[examples-ps-module]:https://msdn.microsoft.com/library/dd878340%28v=vs.85%29.aspx
Expand Down
21 changes: 21 additions & 0 deletions test/powershell/Host/ConsoleHost.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ Describe "ConsoleHost unit tests" -tags "Feature" {
{ & $powershell -input blah -comm { $input } } | Should -Throw -ErrorId "IncorrectValueForFormatParameter"
}
}

Context "CommandLine" {
It "simple -args" {
& $powershell -noprofile { $args[0] } -args "hello world" | Should -Be "hello world"
Expand Down Expand Up @@ -611,6 +612,26 @@ foo
}
}
}

Context "CustomPipeName startup tests" {

It "Should create pipe file if CustomPipeName is specified" {
$pipeName = [System.IO.Path]::GetRandomFileName()
$pipePath = Get-PipePath $pipeName

# The pipePath should be created by the time the -Command is executed.
& $powershell -CustomPipeName $pipeName -Command "Test-Path '$pipePath'" | Should -BeTrue
}

It "Should throw if CustomPipeName is too long on Linux or macOS" -Skip:($IsWindows) {
# Generate a string that is larger than the max pipe name length.
$longPipeName = [string]::new("A", 200)

"`$pid" | & $powershell -CustomPipeName $longPipeName -c -
# 64 is the ExitCode for BadCommandLineParameter
$LASTEXITCODE | Should -Be 64
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we see more user friendly message? Should we check it?

BadCommandLineParameter

Interesting, here parameter is ok but value is not ok.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we see more user friendly message? Should we check it?

Not good to test for that because of Culture since the error message is in a resx.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can check for FullyQualifiedErrorId that is not localized.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adityapatwardhan in this case, I don't think you can because this is not an exception thrown, it's only an EXITCODE that is set along with some error string. It's pwsh.exe trying to start up... not some command that's failing to run.

an example:

.\pwsh.exe -custompipename
Cannot process the command because -CustomPipeName requires an argument that is a name of the pipe you want to use. Specify this argument and try again.

}
}
}

Describe "WindowStyle argument" -Tag Feature {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,134 +1,181 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

$powershell = Join-Path -Path $PsHome -ChildPath "pwsh"

function Wait-JobPid {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like we should have a count limit in the loop, in case the script fails for some reason, and throw on failure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added timeout

param (
$Job
)

# This is to prevent hanging in the test.
$startTime = [DateTime]::Now
$TimeoutInMilliseconds = 10000

# This will receive the pid of the Job process and nothing more since that was the only thing written to the pipeline.
do {
Start-Sleep -Seconds 1
$pwshId = Receive-Job $Job

if (([DateTime]::Now - $startTime).TotalMilliseconds -gt $timeoutInMilliseconds) {
throw "Unable to receive PowerShell process id."
}
} while (!$pwshId)

$pwshId
}

# Executes the Enter/Exit PSHostProcess script that returns the pid of the process that's started.
function Invoke-PSHostProcessScript {
param (
[string] $ArgumentString,
[int] $Id,
[int] $Retry = 5 # Default retry of 5 times
)

$sb = {
# use $i as an incrementally growing pause based on the attempt number
# so that it's more likely to succeed.
$commandStr = @'
Start-Sleep -Seconds {0}
Enter-PSHostProcess {1} -ErrorAction Stop
$pid
Exit-PSHostProcess
'@ -f $i, $ArgumentString

($commandStr | & $powershell -c -) -eq $Id
}

$result = $false
$failures = 0
foreach ($i in 1..$Retry) {
if ($sb.Invoke()) {
$result = $true
break
}

$failures++
}

if($failures) {
Write-Warning "Enter-PSHostProcess script failed $i out of $Retry times."
}

$result
}

Describe "Enter-PSHostProcess tests" -Tag Feature {
Context "By Process Id" {
BeforeAll {
$params = @{
FilePath = "pwsh"
PassThru = $true
RedirectStandardOutput = "TestDrive:\pwsh_out.log"
RedirectStandardError = "TestDrive:\pwsh_err.log"
}
$pwsh = Start-Process @params

if ($IsWindows) {
$params = @{
FilePath = "powershell"
PassThru = $true
RedirectStandardOutput = "TestDrive:\powershell_out.log"
RedirectStandardError = "TestDrive:\powershell_err.log"

BeforeEach {
# Start a normal job where the first thing it does is return $pid. After that, spin forever.
# We will use this job as the target process for Enter-PSHostProcess
$pwshJob = Start-Job {
$pid
while ($true) {
Start-Sleep -Seconds 30 | Out-Null
}
$powershell = Start-Process @params
}

$pwshId = Wait-JobPid $pwshJob
}

AfterAll {
$pwsh | Stop-Process

if ($IsWindows) {
$powershell | Stop-Process
}
AfterEach {
$pwshJob | Stop-Job -PassThru | Remove-Job
}

It "Can enter and exit another PSHost" -Pending:$true {
Wait-UntilTrue { (Get-PSHostProcessInfo -Id $pwsh.Id) -ne $null }
It "Can enter, exit, and re-enter another PSHost" {
Wait-UntilTrue { [bool](Get-PSHostProcessInfo -Id $pwshId) }

"Enter-PSHostProcess -Id $($pwsh.Id) -ErrorAction Stop
`$pid
Exit-PSHostProcess" | pwsh -c - | Should -Be $pwsh.Id
# This will enter and exit another process
Invoke-PSHostProcessScript -ArgumentString "-Id $pwshId" -Id $pwshId |
Should -BeTrue -Because "The script was able to enter another process and grab the pid of '$pwshId'."

# Re-enter and exit the other process
Invoke-PSHostProcessScript -ArgumentString "-Id $pwshId" -Id $pwshId |
Should -BeTrue -Because "The script was able to re-enter another process and grab the pid of '$pwshId'."
}

It "Can enter and exit another Windows PowerShell PSHost" -Skip:(!$IsWindows) {
Wait-UntilTrue { (Get-PSHostProcessInfo -Id $powershell.Id) -ne $null }
It "Can enter, exit, and re-enter another Windows PowerShell PSHost" -Skip:(!$IsWindows) {
# Start a Windows PowerShell job where the first thing it does is return $pid. After that, spin forever.
# We will use this job as the target process for Enter-PSHostProcess
$powershellJob = Start-Job -PSVersion 5.1 {
$pid
while ($true) {
Start-Sleep -Seconds 30 | Out-Null
}
}

"Enter-PSHostProcess -Id $($powershell.Id) -ErrorAction Stop
`$pid
Exit-PSHostProcess" | pwsh -c - | Should -Be $powershell.Id
$powershellId = Wait-JobPid $powershellJob

try {
Wait-UntilTrue { [bool](Get-PSHostProcessInfo -Id $powershellId) }

# This will enter and exit another process
Invoke-PSHostProcessScript -ArgumentString "-Id $powershellId" -Id $powershellId |
Should -BeTrue -Because "The script was able to enter another process and grab the pid of '$powershellId'."

# Re-enter and exit the other process
Invoke-PSHostProcessScript -ArgumentString "-Id $powershellId" -Id $powershellId |
Should -BeTrue -Because "The script was able to re-enter another process and grab the pid of '$powershellId'."

} finally {
$powershellJob | Stop-Job -PassThru | Remove-Job
}
}

It "Can enter using NamedPipeConnectionInfo" -Pending:$true {
It "Can enter using NamedPipeConnectionInfo" {
try {
$npInfo = [System.Management.Automation.Runspaces.NamedPipeConnectionInfo]::new($pwsh.Id)
Wait-UntilTrue { [bool](Get-PSHostProcessInfo -Id $pwshId) }

$npInfo = [System.Management.Automation.Runspaces.NamedPipeConnectionInfo]::new($pwshId)
$rs = [runspacefactory]::CreateRunspace($npInfo)
$rs.Open()
$ps = [powershell]::Create()
$ps.Runspace = $rs
$ps.AddScript('$pid').Invoke() | Should -Be $pwsh.Id
$ps.AddScript('$pid').Invoke() | Should -Be $pwshId
} finally {
$rs.Dispose()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add $ps.Dispose()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

$ps.Dispose()
}
}
}

Context "By CustomPipeName" {
BeforeAll {
# Helper function to get the correct path for the named pipe.
function Get-PipePath {
param (
$PipeName
)
if ($IsWindows) {
return "\\.\pipe\$PipeName"
}
"$([System.IO.Path]::GetTempPath())CoreFxPipe_$PipeName"
}

It "Can enter, exit, and re-enter using CustomPipeName" {
$pipeName = [System.IO.Path]::GetRandomFileName()
$params = @{
FilePath = "pwsh"
ArgumentList = @("-CustomPipeName",$pipeName)
PassThru = $true
RedirectStandardOutput = "TestDrive:\pwsh_out.log"
RedirectStandardError = "TestDrive:\pwsh_err.log"
}
$pwsh = Start-Process @params

$pipePath = Get-PipePath -PipeName $pipeName
}

AfterAll {
$pwsh | Stop-Process
}
# Start a job where the first thing it does is set the custom pipe name, then return $pid.
# After that, spin forever.
# We will use this job as the target process for Enter-PSHostProcess
$pwshJob = Start-Job -ArgumentList $pipeName {
[System.Management.Automation.Remoting.RemoteSessionNamedPipeServer]::CreateCustomNamedPipeServer($args[0])
$pid
while ($true) { Start-Sleep -Seconds 30 | Out-Null }
}

It "Can enter using CustomPipeName" -Pending:$true {
Wait-UntilTrue { Test-Path $pipePath }
$pwshId = Wait-JobPid $pwshJob

"Enter-PSHostProcess -CustomPipeName $pipeName -ErrorAction Stop
`$pid
Exit-PSHostProcess" | pwsh -c - | Should -Be $pwsh.Id
}
try {
Wait-UntilTrue { Test-Path $pipePath }

It "Can enter, exit, and re-enter using CustomPipeName" -Pending:$true {
Wait-UntilTrue { Test-Path $pipePath }
# This will enter and exit another process
Invoke-PSHostProcessScript -ArgumentString "-CustomPipeName $pipeName" -Id $pwshId |
Should -BeTrue -Because "The script was able to enter another process and grab the pipe of '$pipeName'."

"Enter-PSHostProcess -CustomPipeName $pipeName -ErrorAction Stop
`$pid
Exit-PSHostProcess" | pwsh -c - | Should -Be $pwsh.Id
# Re-enter and exit the other process
Invoke-PSHostProcessScript -ArgumentString "-CustomPipeName $pipeName" -Id $pwshId |
Should -BeTrue -Because "The script was able to re-enter another process and grab the pipe of '$pipeName'."

"Enter-PSHostProcess -CustomPipeName $pipeName -ErrorAction Stop
`$pid
Exit-PSHostProcess" | pwsh -c - | Should -Be $pwsh.Id
} finally {
$pwshJob | Stop-Job -PassThru | Remove-Job
}
}

It "Should throw if CustomPipeName does not exist" {
Wait-UntilTrue { Test-Path $pipePath }

{ Enter-PSHostProcess -CustomPipeName badpipename } | Should -Throw -ExpectedMessage "No named pipe was found with CustomPipeName: badpipename."
}

It "Should throw if CustomPipeName is too long on Linux or macOS" {
$longPipeName = "DoggoipsumwaggywagssmolborkingdoggowithalongsnootforpatsdoingmeafrightenporgoYapperporgolongwatershoobcloudsbigolpupperlengthboy"

if (!$IsWindows) {
"`$pid" | pwsh -CustomPipeName $longPipeName -c -
# 64 is the ExitCode for BadCommandLineParameter
$LASTEXITCODE | Should -Be 64
} else {
"`$pid" | pwsh -CustomPipeName $longPipeName -c -
$LASTEXITCODE | Should -Be 0
}
}
}
}
2 changes: 1 addition & 1 deletion test/tools/Modules/HelpersRemoting/HelpersRemoting.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.'

Description = 'Temporary module for remoting tests'

FunctionsToExport = 'New-RemoteRunspace', 'New-RemoteSession', 'Enter-RemoteSession', 'Invoke-RemoteCommand', 'Connect-RemoteSession', 'New-RemoteRunspacePool'
FunctionsToExport = 'New-RemoteRunspace', 'New-RemoteSession', 'Enter-RemoteSession', 'Invoke-RemoteCommand', 'Connect-RemoteSession', 'New-RemoteRunspacePool', 'Get-PipePath'

}
10 changes: 10 additions & 0 deletions test/tools/Modules/HelpersRemoting/HelpersRemoting.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,13 @@ function Connect-RemoteSession
$parameters = CreateParameters -ComputerName $ComputerName -Name $Name -Session $Session -ConfigurationName $ConfigurationName
Connect-PSSession @parameters
}

function Get-PipePath {
param (
$PipeName
)
if ($IsWindows) {
return "\\.\pipe\$PipeName"
}
"$([System.IO.Path]::GetTempPath())CoreFxPipe_$PipeName"
}