diff --git a/contrib/win32/openssh/AzDOBuildTools/AzDOBuildTools.psm1 b/contrib/win32/openssh/AzDOBuildTools/AzDOBuildTools.psm1 index e4f3eec1ec56..742191ea6bb1 100644 --- a/contrib/win32/openssh/AzDOBuildTools/AzDOBuildTools.psm1 +++ b/contrib/win32/openssh/AzDOBuildTools/AzDOBuildTools.psm1 @@ -47,7 +47,7 @@ function Invoke-AzDOBuild function Install-OpenSSH { [CmdletBinding()] - param ( + param ( [Parameter(Mandatory=$true)] [string]$SourceDir, @@ -62,7 +62,7 @@ function Install-OpenSSH Copy-Item -Path "$SourceDir/*" -Destination $OpenSSHDir -Recurse -Force -Verbose - Push-Location $OpenSSHDir + Push-Location $OpenSSHDir try { @@ -81,8 +81,8 @@ function Install-OpenSSH { [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') } - - Start-Service -Name sshd + + Start-Service -Name sshd Start-Service -Name ssh-agent } finally @@ -100,7 +100,7 @@ function Install-OpenSSH function UnInstall-OpenSSH { [CmdletBinding()] - param ( + param ( [string]$OpenSSHDir = "$env:SystemDrive\OpenSSH" ) @@ -117,15 +117,15 @@ function UnInstall-OpenSSH Stop-Service ssh-agent -Force } & "$OpenSSHDir\uninstall-sshd.ps1" - + $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') $newMachineEnvironmentPath = $machinePath if ($machinePath.ToLower().Contains($OpenSSHDir.ToLower())) - { + { $newMachineEnvironmentPath = $newMachineEnvironmentPath.Replace("$OpenSSHDir;", '') $env:Path = $env:Path.Replace("$OpenSSHDir;", '') } - + if ($newMachineEnvironmentPath -ne $machinePath) { [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') @@ -136,7 +136,7 @@ function UnInstall-OpenSSH Pop-Location } - Remove-Item -Path $OpenSSHDir -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Path $OpenSSHDir -Recurse -Force -ErrorAction SilentlyContinue } # @@ -181,7 +181,7 @@ function Invoke-OpenSSHTests } $xml = [xml](Get-Content $OpenSSHTestInfo["SetupTestResultsFile"] | out-string) - if ([int]$xml.'test-results'.failures -gt 0) + if ([int]$xml.'test-results'.failures -gt 0) { $errorMessage = "$($xml.'test-results'.failures) Setup Tests in regress\pesterTests failed. Detail test log is at $($OpenSSHTestInfo["SetupTestResultsFile"])." Write-BuildMessage -Message $errorMessage -Category Error @@ -218,31 +218,9 @@ function Invoke-OpenSSHTests # Run all E2E tests. Write-Verbose -Verbose -Message "Running E2E Tests..." Set-OpenSSHTestEnvironment -Confirm:$false - Invoke-OpenSSHE2ETest - if (($OpenSSHTestInfo -eq $null) -or (-not (Test-Path $OpenSSHTestInfo["E2ETestResultsFile"]))) - { - Write-BuildMessage -Message "Test result file $OpenSSHTestInfo["E2ETestResultsFile"] not found after tests." -Category Error - $AllTestsPassed = $false - } - else - { - $xml = [xml](Get-Content $OpenSSHTestInfo["E2ETestResultsFile"] | out-string) - if ([int]$xml.'test-results'.failures -gt 0) - { - $errorMessage = "$($xml.'test-results'.failures) E2E tests in regress\pesterTests failed. Detail test log is at $($OpenSSHTestInfo["E2ETestResultsFile"])." - Write-BuildMessage -Message $errorMessage -Category Error - $AllTestsPassed = $false - } - else - { - Write-BuildMessage -Message "All E2E tests passed!" -Category Information - } - } - - # Bash tests. - Write-Verbose -Verbose -Message "Running Bash Tests..." # Ensure CygWin is installed, and install from Chocolatey if needed. + # used for bash tests and default shell pester tests $cygwinInstalled = $true $cygwinInstallLocation = "$env:SystemDrive/cygwin" if (! (Test-Path -Path "$cygwinInstallLocation/bin/sh.exe")) @@ -269,9 +247,33 @@ function Invoke-OpenSSHTests } } - # Run UNIX bash tests. if ($cygwinInstalled) { + Invoke-OpenSSHE2ETest + if (($OpenSSHTestInfo -eq $null) -or (-not (Test-Path $OpenSSHTestInfo["E2ETestResultsFile"]))) + { + Write-BuildMessage -Message "Test result file $OpenSSHTestInfo["E2ETestResultsFile"] not found after tests." -Category Error + $AllTestsPassed = $false + } + else + { + $xml = [xml](Get-Content $OpenSSHTestInfo["E2ETestResultsFile"] | out-string) + if ([int]$xml.'test-results'.failures -gt 0) + { + $errorMessage = "$($xml.'test-results'.failures) E2E tests in regress\pesterTests failed. Detail test log is at $($OpenSSHTestInfo["E2ETestResultsFile"])." + Write-BuildMessage -Message $errorMessage -Category Error + $AllTestsPassed = $false + } + else + { + Write-BuildMessage -Message "All E2E tests passed!" -Category Information + } + } + + # Bash tests. + Write-Verbose -Verbose -Message "Running Bash Tests..." + + # Run UNIX bash tests. Write-Verbose -Verbose -Message "Starting Bash Tests..." Invoke-OpenSSHBashTests if (-not $Global:bash_tests_summary) @@ -306,7 +308,7 @@ function Invoke-OpenSSHTests else { $xml = [xml](Get-Content $OpenSSHTestInfo["UninstallTestResultsFile"] | out-string) - if ([int]$xml.'test-results'.failures -gt 0) + if ([int]$xml.'test-results'.failures -gt 0) { $errorMessage = "$($xml.'test-results'.failures) uninstall tests in regress\pesterTests failed. Detail test log is at $($OpenSSHTestInfo["UninstallTestResultsFile"])." Write-BuildMessage -Message $errorMessage -Category Error @@ -318,7 +320,7 @@ function Invoke-OpenSSHTests $OpenSSHTestInfo | Export-Clixml -Path "$repoRoot/OpenSSHTestInfo.xml" -Depth 10 # Writing out warning when the $Error.Count is non-zero. Tests Should clean $Error after success. - if ($Error.Count -gt 0) + if ($Error.Count -gt 0) { Write-BuildMessage -Message "Tests Should always clean $Error variable after success." -Category Warning } @@ -339,7 +341,7 @@ function Invoke-OpenSSHTests Collect OpenSSH pester test results into one directory #> function Copy-OpenSSHTestResults -{ +{ param ( [Parameter(Mandatory=$true)] [string] $ResultsPath @@ -352,7 +354,7 @@ function Copy-OpenSSHTestResults Write-Verbose -Verbose "Creating test results directory for artifacts upload: $ResultsPath" $null = New-Item -Path $ResultsPath -ItemType Directory -Force - + if (! (Test-Path -Path $ResultsPath)) { Write-BuildMessage -Message "Unable to write to test results path for test artifacts upload: $ResultsPath" -Category Error @@ -498,7 +500,7 @@ function Copy-UnitTests function Install-UnitTests { [CmdletBinding()] - param ( + param ( [Parameter(Mandatory=$true)] [string]$SourceDir, diff --git a/regress/pesterTests/SCP.Tests.ps1 b/regress/pesterTests/SCP.Tests.ps1 index 1c3580c83804..ed72177637af 100644 --- a/regress/pesterTests/SCP.Tests.ps1 +++ b/regress/pesterTests/SCP.Tests.ps1 @@ -24,7 +24,7 @@ Describe "Tests for scp command" -Tags "CI" { $SourceFileWildCardFile1 = Join-Path $SourceDir $wildcardFileName1 $DestinationDir = Join-Path "$($OpenSSHTestInfo["TestDataPath"])\SCP" "DestDir" $DestinationDirWildcardPath = Join-Path "$($OpenSSHTestInfo["TestDataPath"])\SCP" "DestD?r" - $DestinationFilePath = Join-Path $DestinationDir $fileName1 + $DestinationFilePath = Join-Path $DestinationDir $fileName1 $NestedSourceDir= Join-Path $SourceDir "nested" $NestedSourceFilePath = Join-Path $NestedSourceDir $fileName2 $null = New-Item $SourceDir -ItemType directory -Force -ErrorAction SilentlyContinue @@ -35,7 +35,7 @@ Describe "Tests for scp command" -Tags "CI" { "Test content333" | Set-content -Path $SourceFilePath3 "Test content in nested dir" | Set-content -Path $NestedSourceFilePath $null = New-Item $DestinationDir -ItemType directory -Force -ErrorAction SilentlyContinue - $sshcmd = (get-command ssh).Path + $sshcmd = (get-command ssh).Path # for symlink tests $SourceDirSymLinkName = "SourceDirSymLink" @@ -50,6 +50,11 @@ Describe "Tests for scp command" -Tags "CI" { $SymLinkDir = Join-Path $SourceDirSymLink $SymLinkName $null = New-Item -Path $SymLinkDir -ItemType SymbolicLink -Value $tmpDir + # for large file transfer tests + $largeFileName = 'largefile.txt' + $largeFilePath = Join-Path $sourceDir $largeFileName + fsutil file createNew $largeFilePath 1000000000 + $server = $OpenSSHTestInfo["Target"] $port = $OpenSSHTestInfo["Port"] $ssouser = $OpenSSHTestInfo["SSOUser"] @@ -57,7 +62,7 @@ Describe "Tests for scp command" -Tags "CI" { $testData = @( @{ Title = 'Simple copy local file to local file' - Source = $SourceFilePath + Source = $SourceFilePath Destination = $DestinationFilePath }, @{ @@ -71,14 +76,14 @@ Describe "Tests for scp command" -Tags "CI" { Source = "test_target:$SourceFilePath" Destination = $DestinationFilePath Options = "-p -c aes128-ctr -C" - }, + }, @{ Title = 'Simple copy local file to local dir' Source = $SourceFilePath Destination = $DestinationDir }, @{ - Title = 'simple copy local file to remote dir' + Title = 'simple copy local file to remote dir' Source = $SourceFilePath Destination = "test_target:$DestinationDir" Options = "-C -q" @@ -99,7 +104,7 @@ Describe "Tests for scp command" -Tags "CI" { Destination = $DestinationDir }, @{ - Title = 'simple copy local file to remote dir with wild card name' + Title = 'simple copy local file to remote dir with wild card name' Source = $SourceFilePath Destination = "test_target:$DestinationFilePath" Options = "-C -q" @@ -120,7 +125,7 @@ Describe "Tests for scp command" -Tags "CI" { Options = "-r " }, @{ - Title = 'copy from remote dir to local dir' + Title = 'copy from remote dir to local dir' Source = "test_target:$sourceDir" Destination = $DestinationDir Options = "-C -r -q" @@ -141,13 +146,28 @@ Describe "Tests for scp command" -Tags "CI" { Options = "-r " }, @{ - Title = 'symlink copy from remote dir to local dir' + Title = 'symlink copy from remote dir to local dir' Source = "test_target:$SourceDirSymLink" Destination = $DestinationDir Options = "-C -r -q" } ) + $testData3 = @( + @{ + Title = 'copy large file from local dir to remote dir' + Source = $largeFilePath + Destination = "test_target:$DestinationDir" + Options = "-S `"$sshcmd`"" + }, + @{ + Title = 'copy large file from remote dir to local dir' + Source = "test_target:$largeFilePath" + Destination = $DestinationDir + Options = "-p -c aes128-ctr -C" + } + ) + # for the first time, delete the existing log files. if ($OpenSSHTestInfo['DebugMode']) { @@ -163,16 +183,32 @@ Describe "Tests for scp command" -Tags "CI" { { Copy-Item "$env:ProgramData\ssh\logs\ssh-agent.log" "$testDir\failedagent$tI.log" -Force -ErrorAction SilentlyContinue Copy-Item "$env:ProgramData\ssh\logs\sshd.log" "$testDir\failedsshd$tI.log" -Force -ErrorAction SilentlyContinue - + # clear the ssh-agent, sshd logs so that next testcase will get fresh logs. Clear-Content "$env:ProgramData\ssh\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue Clear-Content "$env:ProgramData\ssh\logs\sshd.log" -Force -ErrorAction SilentlyContinue } - + return $false } return $true } + + function ConfigureDefaultShell { + param + ( + [string] $default_shell_path, + [string] $default_shell_cmd_option_val = $null + ) + + if (!(Test-Path $dfltShellRegPath)) { + New-Item -Path $dfltShellRegPath -Force | Out-Null + } + New-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -Value $default_shell_path -PropertyType String -Force + if ($default_shell_cmd_option_val -ne $null) { + New-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -Value $default_shell_cmd_option_val -PropertyType String -Force + } + } } AfterAll { @@ -197,82 +233,151 @@ Describe "Tests for scp command" -Tags "CI" { } } - BeforeAll { - $null = New-Item $DestinationDir -ItemType directory -Force -ErrorAction SilentlyContinue - } - AfterEach { Get-ChildItem $DestinationDir -Recurse | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue Start-Sleep 1 $tI++ - } - - - It 'File copy: ' -TestCases:$testData { - param([string]$Title, $Source, $Destination, [string]$Options) - iex "scp $Options $Source $Destination" - $LASTEXITCODE | Should Be 0 - #validate file content. DestPath is the path to the file. - CheckTarget -target $DestinationFilePath | Should Be $true - - $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length ).Length -eq 0 - $equal | Should Be $true - - if($Options.contains("-p ") -and [environment]::OSVersion.Version.Major -ge 10) - { - $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath).LastWriteTime.DateTime (Get-ChildItem -path $DestinationFilePath).LastWriteTime.DateTime ).Length -eq 0 + } + + Context "$tI - Basic Scenarios" { + + It 'File copy: <Title> ' -TestCases:$testData { + param([string]$Title, $Source, $Destination, [string]$Options) + iex "scp $Options $Source $Destination" + $LASTEXITCODE | Should Be 0 + #validate file content. DestPath is the path to the file. + CheckTarget -target $DestinationFilePath | Should Be $true + + $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length ).Length -eq 0 $equal | Should Be $true + + if($Options.contains("-p ") -and [environment]::OSVersion.Version.Major -ge 10) + { + $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath).LastWriteTime.DateTime (Get-ChildItem -path $DestinationFilePath).LastWriteTime.DateTime ).Length -eq 0 + $equal | Should Be $true + } } - } - - It 'Directory recursive copy: <Title> ' -TestCases:$testData1 { - param([string]$Title, $Source, $Destination, [string]$Options) - - iex "scp $Options $Source $Destination" - $LASTEXITCODE | Should Be 0 - CheckTarget -target (join-path $DestinationDir $SourceDirName) | Should Be $true - - $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 - $equal | Should Be $true - - if($Options.contains("-p ")) - { - $equal = @(Compare-Object (Get-Item -path $SourceDir).LastWriteTime.DateTime (Get-Item -path (join-path $DestinationDir $SourceDirName)).LastWriteTime.DateTime).Length -eq 0 + + It 'Directory recursive copy: <Title> ' -TestCases:$testData1 { + param([string]$Title, $Source, $Destination, [string]$Options) + + iex "scp $Options $Source $Destination" + $LASTEXITCODE | Should Be 0 + CheckTarget -target (join-path $DestinationDir $SourceDirName) | Should Be $true + + $equal = @(Compare-Object (Get-Item -path $SourceDir ) (Get-Item -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 + $equal | Should Be $true + + if($Options.contains("-p ")) + { + $equal = @(Compare-Object (Get-Item -path $SourceDir).LastWriteTime.DateTime (Get-Item -path (join-path $DestinationDir $SourceDirName)).LastWriteTime.DateTime).Length -eq 0 + $equal | Should Be $true + } + + $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir) (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 $equal | Should Be $true + + if($Options.contains("-p ") -and $IsWindows -and ($PSVersionTable.PSVersion.Major -gt 2)) + { + $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir).LastWriteTime.DateTime (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ).LastWriteTime.DateTime).Length -eq 0 + $equal | Should Be $true + } } - $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir) (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ) -Property Name, Length).Length -eq 0 - $equal | Should Be $true + It 'Directory with symlink recursive copy: <Title> ' -TestCases:$testData2 { + param([string]$Title, $Source, $Destination, [string]$Options) - if($Options.contains("-p ") -and $IsWindows -and ($PSVersionTable.PSVersion.Major -gt 2)) - { - $equal = @(Compare-Object (Get-ChildItem -Recurse -path $SourceDir).LastWriteTime.DateTime (Get-ChildItem -Recurse -path (join-path $DestinationDir $SourceDirName) ).LastWriteTime.DateTime).Length -eq 0 + iex "scp $Options $Source $Destination" + $LASTEXITCODE | Should Be 0 + $expectedFilepath = join-path $DestinationDir $SourceDirSymLinkName $SymLinkName $fileName1 + CheckTarget -target $expectedFilepath | Should Be $true + Get-Content $expectedFilepath | Should Be "Test content in tmp dir for sym link" + } + + It 'File copy: path contains wildcards ' { + $Source = Join-Path $SourceDir $wildcardFileName2 + scp -p $Source $DestinationDir + $LASTEXITCODE | Should Be 0 + #validate file content. DestPath is the path to the file. + CheckTarget -target $DestinationFilePath | Should Be $true + CheckTarget -target (Join-path $DestinationDir $fileName3) | Should Be $true + + $equal = @(Compare-Object (Get-ChildItem -path $Source) (Get-ChildItem -path (join-path $DestinationDir $wildcardFileName2)) -Property Name, Length ).Length -eq 0 + $equal | Should Be $true + + $equal = @(Compare-Object (Get-ChildItem -path $Source).LastWriteTime.DateTime (Get-ChildItem -path (join-path $DestinationDir $wildcardFileName3)).LastWriteTime.DateTime ).Length -eq 0 $equal | Should Be $true } - } - It 'Directory with symlink recursive copy: <Title> ' -TestCases:$testData2 { - param([string]$Title, $Source, $Destination, [string]$Options) - - iex "scp $Options $Source $Destination" - $LASTEXITCODE | Should Be 0 - $expectedFilepath = join-path $DestinationDir $SourceDirSymLinkName $SymLinkName $fileName1 - CheckTarget -target $expectedFilepath | Should Be $true - Get-Content $expectedFilepath | Should Be "Test content in tmp dir for sym link" + It '<Title> ' -TestCases:$testData3 { + param([string]$Title, $Source, $Destination, [string]$Options) + + iex "scp $Options $Source $Destination" + $LASTEXITCODE | Should Be 0 + + $DestinationFilePath = Join-Path $DestinationDir $largeFileName + CheckTarget -target $DestinationFilePath | Should Be $true + + $equal = @(Compare-Object (Get-ChildItem -path $largeFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length ).Length -eq 0 + $equal | Should Be $true + } } - It 'File copy: path contains wildcards ' { - $Source = Join-Path $SourceDir $wildcardFileName2 - scp -p $Source $DestinationDir - $LASTEXITCODE | Should Be 0 - #validate file content. DestPath is the path to the file. - CheckTarget -target $DestinationFilePath | Should Be $true - CheckTarget -target (Join-path $DestinationDir $fileName3) | Should Be $true - - $equal = @(Compare-Object (Get-ChildItem -path $Source) (Get-ChildItem -path (join-path $DestinationDir $wildcardFileName2)) -Property Name, Length ).Length -eq 0 - $equal | Should Be $true - - $equal = @(Compare-Object (Get-ChildItem -path $Source).LastWriteTime.DateTime (Get-ChildItem -path (join-path $DestinationDir $wildcardFileName3)).LastWriteTime.DateTime ).Length -eq 0 - $equal | Should Be $true + Context "Configure various default shell scenarios" { + BeforeAll { + $dfltShellRegPath = $null + $dfltShellRegPath = "HKLM:\Software\OpenSSH" + $dfltShellRegKeyName = "DefaultShell" + $dfltShellCmdOptionRegKeyName = "DefaultShellCommandOption" + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue + $shells = @( + @{ + Name = "Windows PowerShell" + Path = (Get-Command powershell.exe -ErrorAction SilentlyContinue).Path + CmdOption = "/c" + }, + @{ + Name = "PowerShell Core" + Path = (Get-Command pwsh -ErrorAction SilentlyContinue).Path + CmdOption = $null + }, + @{ + Name = "Bash" + Path = (Get-Command bash -ErrorAction SilentlyContinue).Path + CmdOption = $null + }, + @{ + Name = "Cygwin" + Path = (Get-Command sh -ErrorAction SilentlyContinue).Path + CmdOption = $null + } + ) + } + + AfterEach { + if ($dfltShellRegPath) { + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue + } + } + + It 'File copy: <Name> ' -TestCases:$shells { + param([string]$Name, $Path, $CmdOption) + if ($Path -eq $null) { + throw "$Name not found, please install it to run this test" + } + else { + ConfigureDefaultShell -default_shell_path $Path -default_shell_cmd_option_val $CmdOption + iex "scp test_target:$SourceFilePath $DestinationDir" + $LASTEXITCODE | Should Be 0 + #validate file content. DestPath is the path to the file. + $DestinationFilePath = Join-Path $DestinationDir $fileName1 + CheckTarget -target $DestinationFilePath | Should Be $true + + $equal = @(Compare-Object (Get-ChildItem -path $SourceFilePath) (Get-ChildItem -path $DestinationFilePath) -Property Name, Length ).Length -eq 0 + $equal | Should Be $true + } + } } -} +} diff --git a/regress/pesterTests/SFTP.Tests.ps1 b/regress/pesterTests/SFTP.Tests.ps1 index a0a35f380a76..400778bc8d01 100644 --- a/regress/pesterTests/SFTP.Tests.ps1 +++ b/regress/pesterTests/SFTP.Tests.ps1 @@ -3,194 +3,224 @@ Import-Module $PSScriptRoot\CommonUtils.psm1 -Force $tI = 0 Describe "SFTP Test Cases" -Tags "CI" { BeforeAll { - $serverDirectory = $null - $clientDirectory = $null - if($OpenSSHTestInfo -eq $null) - { - Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments." - } - - $rootDirectory = "$($OpenSSHTestInfo["TestDataPath"])\SFTP" - - $outputFileName = "output.txt" - $batchFileName = "sftp-batchcmds.txt" - $tempFileName = "tempFile.txt" - $tempFilePath = Join-Path $rootDirectory $tempFileName - - $tempUnicodeFileName = "tempFile_язык.txt" - $tempUnicodeFilePath = Join-Path $rootDirectory $tempUnicodeFileName - - $clientDirectory = Join-Path $rootDirectory 'client_dir' - $serverDirectory = Join-Path $rootDirectory 'server_dir' - - $null = New-Item $clientDirectory -ItemType directory -Force - $null = New-Item $serverDirectory -ItemType directory -Force - $null = New-Item $tempFilePath -ItemType file -Force -value "temp file data" - $null = New-Item $tempUnicodeFilePath -ItemType file -Force -value "temp file data" - - $server = $OpenSSHTestInfo["Target"] - $port = $OpenSSHTestInfo["Port"] - $ssouser = $OpenSSHTestInfo["SSOUser"] - - Remove-item (Join-Path $rootDirectory "*.$outputFileName") -Force -ErrorAction SilentlyContinue - Remove-item (Join-Path $rootDirectory "*.$batchFileName") -Force -ErrorAction SilentlyContinue - Remove-item (Join-Path $rootDirectory "*.log") -Force -ErrorAction SilentlyContinue - - $skip = $IsWindows -and ($PSVersionTable.PSVersion.Major -le 2) - - $testData1 = @( - @{ - title = "put, ls for non-unicode file names" - options = '' - commands = "put $tempFilePath $serverDirectory - ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempFileName) - }, + $serverDirectory = $null + $clientDirectory = $null + $largeFilePath = $null + if($OpenSSHTestInfo -eq $null) + { + Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments." + } + $rootDirectory = "$($OpenSSHTestInfo["TestDataPath"])\SFTP" + $outputFileName = "output.txt" + $batchFileName = "sftp-batchcmds.txt" + $tempFileName = "tempFile.txt" + $tempFilePath = Join-Path $rootDirectory $tempFileName + $tempUnicodeFileName = "tempFile_язык.txt" + $tempUnicodeFilePath = Join-Path $rootDirectory $tempUnicodeFileName + $largeFileName = "largeFile.txt" + $largeFilePath = Join-Path $rootDirectory $largeFileName + fsutil file createNew $largeFilePath 1000000000 + $clientDirectory = Join-Path $rootDirectory 'client_dir' + $serverDirectory = Join-Path $rootDirectory 'server_dir' + $null = New-Item $clientDirectory -ItemType directory -Force + $null = New-Item $serverDirectory -ItemType directory -Force + $null = New-Item $tempFilePath -ItemType file -Force -value "temp file data" + $null = New-Item $tempUnicodeFilePath -ItemType file -Force -value "temp file data" + $server = $OpenSSHTestInfo["Target"] + $port = $OpenSSHTestInfo["Port"] + $ssouser = $OpenSSHTestInfo["SSOUser"] + Remove-item (Join-Path $rootDirectory "*.$outputFileName") -Force -ErrorAction SilentlyContinue + Remove-item (Join-Path $rootDirectory "*.$batchFileName") -Force -ErrorAction SilentlyContinue + Remove-item (Join-Path $rootDirectory "*.log") -Force -ErrorAction SilentlyContinue + $skip = $IsWindows -and ($PSVersionTable.PSVersion.Major -le 2) + $testData1 = @( + @{ + title = "put, ls for non-unicode file names" + options = '' + commands = "put $tempFilePath $serverDirectory + ls $serverDirectory" + expectedoutput = (join-path $serverdirectory $tempFileName) + }, + @{ + title = "get, ls for non-unicode file names" + options = '' + commands = "get $tempFilePath $clientDirectory + ls $clientDirectory" + expectedoutput = (join-path $clientDirectory $tempFileName) + }, + @{ + title = "mput, ls for non-unicode file names" + options = '' + commands = "mput $tempFilePath $serverDirectory + ls $serverDirectory" + expectedoutput = (join-path $serverdirectory $tempFileName) + }, + @{ + title = "mget, ls for non-unicode file names" + options = '' + commands = "mget $tempFilePath $clientDirectory + ls $clientDirectory" + expectedoutput = (join-path $clientDirectory $tempFileName) + }, + @{ + title = "mkdir, cd, pwd for non-unicode directory names" + options = '' + commands = "cd $serverdirectory + mkdir server_test_dir + cd server_test_dir + pwd" + expectedoutput = (join-path $serverdirectory "server_test_dir") + }, + @{ + Title = "lmkdir, lcd, lpwd for non-unicode directory names" + Options = '' + Commands = "lcd $clientDirectory + lmkdir client_test_dir + lcd client_test_dir + lpwd" + ExpectedOutput = (Join-Path $clientDirectory "client_test_dir") + }, + @{ + title = "put, ls for unicode file names" + options = '' + commands = "put $tempUnicodeFilePath $serverDirectory + ls $serverDirectory" + expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) + }, + @{ + title = "get, ls for unicode file names" + options = '' + commands = "get $tempUnicodeFilePath $clientDirectory + ls $clientDirectory" + expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) + }, + @{ + title = "mput, ls for unicode file names" + options = '' + commands = "mput $tempUnicodeFilePath $serverDirectory + ls $serverDirectory" + expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) + }, + @{ + title = "mget, ls for unicode file names" + options = '' + commands = "mget $tempUnicodeFilePath $clientDirectory + ls $clientDirectory" + expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) + }, + @{ + title = "mkdir, cd, pwd for unicode directory names" + options = '' + commands = "cd $serverdirectory + mkdir server_test_dir_язык + cd server_test_dir_язык + pwd" + expectedoutput = (join-path $serverdirectory "server_test_dir_язык") + }, + @{ + Title = "lmkdir, lcd, lpwd for unicode directory names" + Options = '' + Commands = "lcd $clientDirectory + lmkdir client_test_dir_язык + lcd client_test_dir_язык + lpwd + lls $clientDirectory" + ExpectedOutput = (Join-Path $clientDirectory "client_test_dir_язык") + } + ) + $testData2 = @( @{ - title = "get, ls for non-unicode file names" - options = '' - commands = "get $tempFilePath $clientDirectory - ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempFileName) + title = "rm, rmdir, rename for unicode file, directory" + options = '-b $batchFilePath' + tmpFileName1 = $tempUnicodeFileName + tmpFilePath1 = $tempUnicodeFilePath + tmpFileName2 = "tempfile_язык_2.txt" + tmpFilePath2 = (join-path $serverDirectory "tempfile_язык_2.txt") + tmpDirectoryName1 = "test_dir_язык_1" + tmpDirectoryPath1 = (join-path $serverDirectory "test_dir_язык_1") + tmpDirectoryName2 = "test_dir_язык_2" + tmpDirectoryPath2 = (join-path $serverDirectory "test_dir_язык_2") }, @{ - title = "mput, ls for non-unicode file names" - options = '' - commands = "mput $tempFilePath $serverDirectory - ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempFileName) - }, - @{ - title = "mget, ls for non-unicode file names" - options = '' - commands = "mget $tempFilePath $clientDirectory - ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempFileName) - }, - @{ - title = "mkdir, cd, pwd for non-unicode directory names" - options = '' - commands = "cd $serverdirectory - mkdir server_test_dir - cd server_test_dir - pwd" - expectedoutput = (join-path $serverdirectory "server_test_dir") - }, - @{ - Title = "lmkdir, lcd, lpwd for non-unicode directory names" - Options = '' - Commands = "lcd $clientDirectory - lmkdir client_test_dir - lcd client_test_dir - lpwd" - ExpectedOutput = (Join-Path $clientDirectory "client_test_dir") - }, + title = "rm, rmdir, rename for non-unicode file, directory" + options = '-b $batchFilePath' + tmpFileName1 = $tempFileName + tmpFilePath1 = $tempFilePath + tmpFileName2 = "tempfile_2.txt" + tmpFilePath2 = (join-path $serverDirectory "tempfile_2.txt") + tmpDirectoryName1 = "test_dir_1" + tmpDirectoryPath1 = (join-path $serverDirectory "test_dir_1") + tmpDirectoryName2 = "test_dir_2" + tmpDirectoryPath2 = (join-path $serverDirectory "test_dir_2") + } + ) + $testData3 = @( @{ - title = "put, ls for unicode file names" - options = '' - commands = "put $tempUnicodeFilePath $serverDirectory + title = "put, ls for large file transfer" + commands = "put $largeFilePath $serverDirectory ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) + expectedoutput = (join-path $serverdirectory $largeFileName) }, @{ - title = "get, ls for unicode file names" - options = '' - commands = "get $tempUnicodeFilePath $clientDirectory + title = "get, ls for large file transfer" + commands = "get $largeFilePath $clientDirectory ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) + expectedoutput = (join-path $clientDirectory $largeFileName) }, @{ - title = "mput, ls for unicode file names" - options = '' - commands = "mput $tempUnicodeFilePath $serverDirectory + title = "mput, ls for large file transfer" + commands = "mput $largeFilePath $serverDirectory ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) + expectedoutput = (join-path $serverdirectory $largeFileName) }, @{ - title = "mget, ls for unicode file names" - options = '' - commands = "mget $tempUnicodeFilePath $clientDirectory + title = "mget, ls for large file transfer" + commands = "mget $largeFilePath $clientDirectory ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) - }, - @{ - title = "mkdir, cd, pwd for unicode directory names" - options = '' - commands = "cd $serverdirectory - mkdir server_test_dir_язык - cd server_test_dir_язык - pwd" - expectedoutput = (join-path $serverdirectory "server_test_dir_язык") - }, - @{ - Title = "lmkdir, lcd, lpwd for unicode directory names" - Options = '' - Commands = "lcd $clientDirectory - lmkdir client_test_dir_язык - lcd client_test_dir_язык - lpwd - lls $clientDirectory" - ExpectedOutput = (Join-Path $clientDirectory "client_test_dir_язык") + expectedoutput = (join-path $clientDirectory $largeFileName) + } + ) + # for the first time, delete the existing log files. + if ($OpenSSHTestInfo['DebugMode']) + { + Clear-Content "$env:ProgramData\ssh\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue + Clear-Content "$env:ProgramData\ssh\logs\sshd.log" -Force -ErrorAction SilentlyContinue + Clear-Content "$env:ProgramData\ssh\logs\sftp-server.log" -Force -ErrorAction SilentlyContinue + } + function CopyDebugLogs { + if($OpenSSHTestInfo["DebugMode"]) + { + Copy-Item "$env:ProgramData\ssh\logs\ssh-agent.log" "$rootDirectory\ssh-agent_$tI.log" -Force -ErrorAction SilentlyContinue + Copy-Item "$env:ProgramData\ssh\logs\sshd.log" "$rootDirectory\sshd_$tI.log" -Force -ErrorAction SilentlyContinue + Copy-Item "$env:ProgramData\ssh\logs\sftp-server.log" "$rootDirectory\sftp-server_$tI.log" -Force -ErrorAction SilentlyContinue + # clear the ssh-agent, sshd logs so that next testcase will get fresh logs. + Clear-Content "$env:ProgramData\ssh\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue + Clear-Content "$env:ProgramData\ssh\logs\sshd.log" -Force -ErrorAction SilentlyContinue + Clear-Content "$env:ProgramData\ssh\logs\sftp-server.log" -Force -ErrorAction SilentlyContinue } - ) - - $testData2 = @( - @{ - title = "rm, rmdir, rename for unicode file, directory" - options = '-b $batchFilePath' - - tmpFileName1 = $tempUnicodeFileName - tmpFilePath1 = $tempUnicodeFilePath - tmpFileName2 = "tempfile_язык_2.txt" - tmpFilePath2 = (join-path $serverDirectory "tempfile_язык_2.txt") + } - tmpDirectoryName1 = "test_dir_язык_1" - tmpDirectoryPath1 = (join-path $serverDirectory "test_dir_язык_1") - tmpDirectoryName2 = "test_dir_язык_2" - tmpDirectoryPath2 = (join-path $serverDirectory "test_dir_язык_2") - }, - @{ - title = "rm, rmdir, rename for non-unicode file, directory" - options = '-b $batchFilePath' - - tmpFileName1 = $tempFileName - tmpFilePath1 = $tempFilePath - tmpFileName2 = "tempfile_2.txt" - tmpFilePath2 = (join-path $serverDirectory "tempfile_2.txt") + function ConfigureDefaultShell { + param + ( + [string] $default_shell_path, + [string] $default_shell_cmd_option_val = $null + ) - tmpDirectoryName1 = "test_dir_1" - tmpDirectoryPath1 = (join-path $serverDirectory "test_dir_1") - tmpDirectoryName2 = "test_dir_2" - tmpDirectoryPath2 = (join-path $serverDirectory "test_dir_2") + if (!(Test-Path $dfltShellRegPath)) { + New-Item -Path $dfltShellRegPath -Force | Out-Null } - ) - - # for the first time, delete the existing log files. - if ($OpenSSHTestInfo['DebugMode']) - { - Clear-Content "$env:ProgramData\ssh\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue - Clear-Content "$env:ProgramData\ssh\logs\sshd.log" -Force -ErrorAction SilentlyContinue - Clear-Content "$env:ProgramData\ssh\logs\sftp-server.log" -Force -ErrorAction SilentlyContinue - } - - function CopyDebugLogs { - if($OpenSSHTestInfo["DebugMode"]) - { - Copy-Item "$env:ProgramData\ssh\logs\ssh-agent.log" "$rootDirectory\ssh-agent_$tI.log" -Force -ErrorAction SilentlyContinue - Copy-Item "$env:ProgramData\ssh\logs\sshd.log" "$rootDirectory\sshd_$tI.log" -Force -ErrorAction SilentlyContinue - Copy-Item "$env:ProgramData\ssh\logs\sftp-server.log" "$rootDirectory\sftp-server_$tI.log" -Force -ErrorAction SilentlyContinue - - # clear the ssh-agent, sshd logs so that next testcase will get fresh logs. - Clear-Content "$env:ProgramData\ssh\logs\ssh-agent.log" -Force -ErrorAction SilentlyContinue - Clear-Content "$env:ProgramData\ssh\logs\sshd.log" -Force -ErrorAction SilentlyContinue - Clear-Content "$env:ProgramData\ssh\logs\sftp-server.log" -Force -ErrorAction SilentlyContinue + New-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -Value $default_shell_path -PropertyType String -Force + if ($default_shell_cmd_option_val -ne $null) { + New-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -Value $default_shell_cmd_option_val -PropertyType String -Force } - } + } } AfterAll { if($serverDirectory) { Get-ChildItem $serverDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue } if($clientDirectory) { Get-ChildItem $clientDirectory | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue } + if($largeFilePath) { Remove-Item $largeFilePath -Force -ErrorAction SilentlyContinue } } BeforeEach { @@ -203,11 +233,10 @@ Describe "SFTP Test Cases" -Tags "CI" { AfterEach { CopyDebugLogs $tI++ - } + } It '<Title>' -TestCases:$testData1 { param([string]$Title, $Options, $Commands, $ExpectedOutput) - Set-Content $batchFilePath -Encoding UTF8 -value $Commands $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port $($Options) -b $batchFilePath test_target > $outputFilePath") iex $str @@ -270,9 +299,9 @@ Describe "SFTP Test Cases" -Tags "CI" { } It "$script:testId-ls lists items the user has no read permission" { - $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid) + $adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid) $currentUserSid = Get-UserSID -User "$($env:USERDOMAIN)\$($env:USERNAME)" - + $permTestHasAccessFile = "permTestHasAccessFile.txt" $permTestHasAccessFilePath = Join-Path $serverDirectory $permTestHasAccessFile Remove-Item $permTestHasAccessFilePath -Force -ErrorAction SilentlyContinue @@ -289,7 +318,7 @@ Describe "SFTP Test Cases" -Tags "CI" { $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -b $batchFilePath test_target > $outputFilePath") iex $str $content = Get-Content $outputFilePath - + #cleanup $HasAccessPattern = $permTestHasAccessFilePath.Replace("\", "[/\\]") $matches = @($content | select-string -Pattern "^/$HasAccessPattern\s{0,}$") @@ -299,4 +328,77 @@ Describe "SFTP Test Cases" -Tags "CI" { $matches = @($content | select-string -Pattern "^/$NoAccessPattern\s{0,}$") $matches.count | Should be 1 } + + It '<Title>' -TestCases:$testData3 { + param([string]$Title, $Commands, $ExpectedOutput) + if (-not (Test-Path $largeFilePath)) { + fsutil file createNew $largeFilePath 1000000000 + } + Set-Content $batchFilePath -Encoding UTF8 -value $Commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port -b $batchFilePath test_target > $outputFilePath") + iex $str + + #validate file content. + Test-Path $ExpectedOutput | Should be $true + $LASTEXITCODE | Should Be 0 + } + + Context "Configure various default shell scenarios" { + BeforeAll { + $dfltShellRegPath = $null + $dfltShellRegPath = "HKLM:\Software\OpenSSH" + $dfltShellRegKeyName = "DefaultShell" + $dfltShellCmdOptionRegKeyName = "DefaultShellCommandOption" + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue + $shells = @( + @{ + Name = "Windows PowerShell" + Path = (Get-Command powershell.exe -ErrorAction SilentlyContinue).Path + CmdOption = "/c" + }, + @{ + Name = "PowerShell Core" + Path = (Get-Command pwsh -ErrorAction SilentlyContinue).Path + CmdOption = $null + }, + @{ + Name = "Bash" + Path = (Get-Command bash -ErrorAction SilentlyContinue).Path + CmdOption = $null + }, + @{ + Name = "Cygwin" + Path = (Get-Command sh -ErrorAction SilentlyContinue).Path + CmdOption = $null + } + ) + } + + AfterEach { + if ($dfltShellRegPath) { + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -ErrorAction SilentlyContinue + Remove-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -ErrorAction SilentlyContinue + } + } + + It 'File copy: <Name> ' -TestCases:$shells { + param([string]$Name, $Path, $CmdOption) + if ($Path -eq $null) { + throw "$Name not found, please install it to run this test" + } + else { + ConfigureDefaultShell -default_shell_path $Path -default_shell_cmd_option_val $CmdOption + $Commands = "put $tempFilePath $serverDirectory + ls $serverDirectory" + Set-Content $batchFilePath -Encoding UTF8 -value $Commands + $str = $ExecutionContext.InvokeCommand.ExpandString("sftp -P $port -b $batchFilePath test_target > $outputFilePath") + iex $str + + #validate file content. + $ExpectedOutput = (join-path $serverdirectory $tempFileName) + Test-Path $ExpectedOutput | Should be $true + } + } + } } diff --git a/regress/pesterTests/SSH.Tests.ps1 b/regress/pesterTests/SSH.Tests.ps1 index ab66ad290db5..c545c9bffac4 100644 --- a/regress/pesterTests/SSH.Tests.ps1 +++ b/regress/pesterTests/SSH.Tests.ps1 @@ -265,7 +265,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" { It "$tC.$tI - admin session can write to console" -skip:$skip { $adminusername = $OpenSSHTestInfo['AdminUser'] $o = ssh $adminusername@test_target "Get-ComputerInfo" - $LASTEXITCODE | Should Be 0 + $LASTEXITCODE | Should Be 0 $o | Select-String -Pattern "WindowsVersion" | Should Match "WindowsVersion" } } @@ -405,5 +405,11 @@ Describe "E2E scenarios for ssh client" -Tags "CI" { iex "cmd /c `"ssh -o ProxyCommand=`"`"$($env:ComSpec) /c echo test string for invalid proxy 1>&2`"`" abc 2>$stderrFile`"" $stderrFile | Should Contain "test string for invalid proxy" } + + It "$tC.$tI - disable pseudo-terminal allocation (-T)" { + $o = ssh -T test_target echo 1234 + $LASTEXITCODE | Should Be 0 + $o | Should Be "1234" + } } } diff --git a/regress/pesterTests/Terminal.Tests.ps1 b/regress/pesterTests/Terminal.Tests.ps1 new file mode 100644 index 000000000000..36b6bf27a725 --- /dev/null +++ b/regress/pesterTests/Terminal.Tests.ps1 @@ -0,0 +1,45 @@ +param( + #skip if non-interactive session + [bool]$Skip=$true + ) + +If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path} +Import-Module $PSScriptRoot\CommonUtils.psm1 -Force + +$tC = 1 +$tI = 0 +$suite = "sshclientterminal" + +Describe "E2E scenarios for an interactive terminal" -Tags "CI" { + BeforeAll { + if($OpenSSHTestInfo -eq $null) + { + Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments." + } + $ssouser = $OpenSSHTestInfo["SSOUser"] + $testDir = Join-Path $OpenSSHTestInfo["TestDataPath"] $suite + if(-not (Test-Path $testDir)) + { + $null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue + } + $acl = Get-Acl $testDir + $rights = [System.Security.AccessControl.FileSystemRights]"Read, Write" + $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($ssouser, $rights, "ContainerInherit,Objectinherit", "None", "Allow") + $acl.SetAccessRule($accessRule) + Set-Acl -Path $testDir -AclObject $acl + } + + AfterEach {$tI++;} + + Context "$tC - Basic Scenarios" { + + BeforeAll {$tI=1} + AfterAll{$tC++} + + It "$tC.$tI - force pseudo-terminal allocation (-t)" -Skip:$Skip { + $o = ssh -t test_target echo 1234 + $LASTEXITCODE | Should Be 0 + $o[0].Contains("1234") | Should Be $true + } + } +}