From 17efb12f6fddea38fb1a7f56f56523ede6666a5f Mon Sep 17 00:00:00 2001 From: Manoj Ampalam Date: Fri, 12 May 2017 10:31:59 -0700 Subject: [PATCH] ssh client E2E tests (#138) https://github.com/PowerShell/Win32-OpenSSH/issues/619 PowerShell/Win32-OpenSSH#623 * C2 * C3 * C4 * C5 --- contrib/win32/openssh/OpenSSHTestHelper.psm1 | 53 ++++++++++++++- contrib/win32/win32compat/misc.c | 3 +- regress/pesterTests/SSH.Tests.ps1 | 70 ++++++++++++++++---- 3 files changed, 109 insertions(+), 17 deletions(-) diff --git a/contrib/win32/openssh/OpenSSHTestHelper.psm1 b/contrib/win32/openssh/OpenSSHTestHelper.psm1 index cec2f71a6..cfbd1dfcf 100644 --- a/contrib/win32/openssh/OpenSSHTestHelper.psm1 +++ b/contrib/win32/openssh/OpenSSHTestHelper.psm1 @@ -212,6 +212,7 @@ WARNING: Following changes will be made to OpenSSH configuration $testPriKeypath = Join-Path $Script:E2ETestDirectory sshtest_userssokey_ed25519 Cleanup-SecureFileACL -FilePath $testPriKeypath -owner $owner cmd /c "ssh-add $testPriKeypath 2>&1 >> $Script:TestSetupLogFile" + Backup-OpenSSHTestInfo } #TODO - this is Windows specific. Need to be in PAL function Get-LocalUserProfile @@ -439,6 +440,56 @@ function Run-OpenSSHUnitTest $testfailed } +function Backup-OpenSSHTestInfo +{ + param + ( + [string] $BackupFile = $null + ) + + if ($Global:OpenSSHTestInfo -eq $null) { + Throw "`$OpenSSHTestInfo is null. Did you run Setup-OpenSSHTestEnvironment yet?" + } + + $testInfo = $Global:OpenSSHTestInfo + + if ([String]::IsNullOrEmpty($BackupFile)) { + $BackupFile = Join-Path $testInfo["TestDataPath"] "OpenSSHTestInfo_backup.txt" + } + + $null | Set-Content $BackupFile + + foreach ($key in $testInfo.Keys) { + $value = $testInfo[$key] + Add-Content $BackupFile "$key,$value" + } +} + +function Recover-OpenSSHTestInfo +{ + param + ( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $BackupFile + ) + + if($Global:OpenSSHTestInfo -ne $null) + { + $Global:OpenSSHTestInfo.Clear() + $Global:OpenSSHTestInfo = $null + } + + $Global:OpenSSHTestInfo = @{} + + $entries = Get-Content $BackupFile + + foreach ($entry in $entries) { + $data = $entry.Split(",") + $Global:OpenSSHTestInfo[$data[0]] = $data[1] + } +} + <# Write-Log #> @@ -460,4 +511,4 @@ function Write-Log } } -Export-ModuleMember -Function Setup-OpenSSHTestEnvironment, Cleanup-OpenSSHTestEnvironment, Run-OpenSSHUnitTest, Run-OpenSSHE2ETest +Export-ModuleMember -Function Setup-OpenSSHTestEnvironment, Cleanup-OpenSSHTestEnvironment, Run-OpenSSHUnitTest, Run-OpenSSHE2ETest, Backup-OpenSSHTestInfo, Recover-OpenSSHTestInfo diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c index 068fb4bf3..1f9670c1b 100644 --- a/contrib/win32/win32compat/misc.c +++ b/contrib/win32/win32compat/misc.c @@ -117,7 +117,7 @@ char* _sys_errlist_ext[] = { "No STREAM resources", /* ENOSR 124 */ "Not a STREAM", /* ENOSTR 125 */ "The socket is not connected", /* ENOTCONN 126 */ - "enotecoverable", /* ENOTRECOVERABLE 127 */ + "enotrecoverable", /* ENOTRECOVERABLE 127 */ "Not a socket", /* ENOTSOCK 128 */ "Operation not supported", /* ENOTSUP 129 */ "Operation not supported on socket", /* EOPNOTSUPP 130 */ @@ -256,7 +256,6 @@ w32_fopen_utf8(const char *path, const char *mode) } f = _wfopen(wpath, wmode); - if (f) { /* BOM adjustments for file streams*/ if (mode[0] == 'w' && fseek(f, 0, SEEK_SET) != EBADF) { diff --git a/regress/pesterTests/SSH.Tests.ps1 b/regress/pesterTests/SSH.Tests.ps1 index d6c910d09..e1a93b32d 100644 --- a/regress/pesterTests/SSH.Tests.ps1 +++ b/regress/pesterTests/SSH.Tests.ps1 @@ -3,7 +3,7 @@ $tC = 1 $tI = 0 -Describe "ssh client tests" -Tags "CI" { +Describe "E2E scenarios for ssh client" -Tags "CI" { BeforeAll { if($OpenSSHTestInfo -eq $null) { @@ -73,7 +73,9 @@ Describe "ssh client tests" -Tags "CI" { BeforeEach { $tI++; - $tFile=Join-Path $testDir "$tC.$tI.txt" + $stderrFile=Join-Path $testDir "$tC.$tI.stderr.txt" + $stdoutFile=Join-Path $testDir "$tC.$tI.stdout.txt" + $logFile = Join-Path $testDir "$tC.$tI.log.txt" } Context "$tC - Basic Scenarios" { @@ -82,24 +84,30 @@ Describe "ssh client tests" -Tags "CI" { AfterAll{$tC++} It "$tC.$tI - test version" { - iex "cmd /c `"ssh -V 2> $tFile`"" - $tFile | Should Contain "OpenSSH_" + iex "cmd /c `"ssh -V 2> $stderrFile`"" + $stderrFile | Should Contain "OpenSSH_" } It "$tC.$tI - test help" { - iex "cmd /c `"ssh -? 2> $tFile`"" - $tFile | Should Contain "usage: ssh" + iex "cmd /c `"ssh -? 2> $stderrFile`"" + $stderrFile | Should Contain "usage: ssh" } It "$tC.$tI - remote echo command" { iex "$sshDefaultCmd echo 1234" | Should Be "1234" } - It "$tC.$tI - exit code" { - ssh -p $port $ssouser@$server exit 0 - $LASTEXITCODE | Should Be 0 - ssh -p $port $ssouser@$server exit 21 - $LASTEXITCODE | Should Be 21 + } + + Context "$tC - exit code (exit-status.sh)" { + BeforeAll {$tI=1} + AfterAll{$tC++} + + It "$tC.$tI - various exit codes" { + foreach ($i in (0,1,4,5,44)) { + ssh -p $port $ssouser@$server exit $i + $LASTEXITCODE | Should Be $i + } } } @@ -109,8 +117,8 @@ Describe "ssh client tests" -Tags "CI" { AfterAll{$tC++} It "$tC.$tI - stdout to file" { - iex "$sshDefaultCmd powershell get-process > $tFile" - $tFile | Should Contain "ProcessName" + iex "$sshDefaultCmd powershell get-process > $stdoutFile" + $stdoutFile | Should Contain "ProcessName" } It "$tC.$tI - stdout to PS object" { @@ -131,7 +139,6 @@ Describe "ssh client tests" -Tags "CI" { AfterAll{$tC++} It "$tC.$tI - verbose to file" { - $logFile = Join-Path $testDir "$tC.$tI.log.txt" $o = ssh -p $port -v -E $logFile $ssouser@$server echo 1234 $o | Should Be "1234" #TODO - checks below are very inefficient (time taking). @@ -139,7 +146,42 @@ Describe "ssh client tests" -Tags "CI" { $logFile | Should Contain "Exit Status 0" } + + It "$tC.$tI - cipher options" { + #bad cipher + iex "cmd /c `"ssh -c bad_cipher $ssouser@$server echo 1234 2>$stderrFile`"" + $stderrFile | Should Contain "Unknown cipher type" + #good cipher, ensure cipher is used from debug logs + $o = ssh -c aes256-ctr -v -E $logFile -p $port $ssouser@$server echo 1234 + $o | Should Be "1234" + $logFile | Should Contain "kex: server->client cipher: aes256-ctr" + $logFile | Should Contain "kex: client->server cipher: aes256-ctr" + } + + It "$tC.$tI - ssh_config" { + #ensure -F is working by pointing to a bad configuration + $badConfigFile = Join-Path $testDir "$tC.$tI.bad_ssh_config" + "bad_config_line" | Set-Content $badConfigFile + iex "cmd /c `"ssh -F $badConfigFile $ssouser@$server echo 1234 2>$stderrFile`"" + $stderrFile | Should Contain "bad_ssh_config" + $stderrFile | Should Contain "bad_config_line" + $stderrFile | Should Contain "bad configuration options" + + #try with a proper configuration file. Put it on a unicode path with unicode content + #so we can test the Unicode support simultaneously + $goodConfigFile = Join-Path $testDir "$tC.$tI.Очень_хорошо_ssh_config" + "#this is a Unicode comment because it contains русский язык" | Set-Content $goodConfigFile -Encoding UTF8 + "Host myhost" | Add-Content $goodConfigFile + " HostName $server" | Add-Content $goodConfigFile + " Port $port" | Add-Content $goodConfigFile + " User $ssouser" | Add-Content $goodConfigFile + $o = ssh -F $goodConfigFile myhost echo 1234 + $o | Should Be "1234" + } } + + + <#Context "Key is not secured in ssh-agent on server" { BeforeAll { $identifyFile = $client.clientPrivateKeyPaths[0]