diff --git a/docker/tests/README.md b/docker/tests/README.md new file mode 100644 index 0000000000..f43ec7b51a --- /dev/null +++ b/docker/tests/README.md @@ -0,0 +1,25 @@ +# Docker tests + +## Windows and Linux containers + +The tests must be run separately on the Windows and Linux docker daemons. You can use the Linux docker daemon on Windows, but that will only test Linux containers not Windows Containers. + +## To building and basic behavior of the containers + +```PowerShell +Invoke-Pester +``` + +Note: be sure to do this using both the Windows and Linux docker daemon, as the windows. + +## To test the productions containers + +```PowerShell +Invoke-Pester -Tag Behavior +``` + +## To test only building the containers + +```PowerShell +Invoke-Pester -Tag Build +``` diff --git a/docker/tests/container.tests.ps1 b/docker/tests/container.tests.ps1 new file mode 100644 index 0000000000..ea6a694bb7 --- /dev/null +++ b/docker/tests/container.tests.ps1 @@ -0,0 +1,104 @@ +Import-module -Name "$PSScriptRoot\containerTestCommon.psm1" -Force +$script:linuxContainerTests = Get-LinuxContainer +$script:windowsContainerTests = Get-WindowsContainer +$script:skipLinux = Test-SkipLinux +$script:skipWindows = Test-SkipWindows + +Describe "Build Linux Containers" -Tags 'Build', 'Linux' { + BeforeAll { + Set-RepoName 'pscontainertest' + } + + it "$(Get-RepoName): builds from ''" -TestCases $script:linuxContainerTests -Skip:$script:skipLinux { + param( + [Parameter(Mandatory=$true)] + [string] + $name, + + [Parameter(Mandatory=$true)] + [string] + $path + ) + { Invoke-Docker -Command build -Params '--pull', '--quiet', '-t', "$(Get-RepoName):${Name}", $path -SuppressHostOutput} | should not throw + } +} + +Describe "Build Windows Containers" -Tags 'Build', 'Windows' { + BeforeAll { + Set-RepoName 'pscontainertest' + } + + it "$(Get-RepoName): builds from ''" -TestCases $script:windowsContainerTests -skip:$script:skipWindows { + param( + [Parameter(Mandatory=$true)] + [string] + $name, + + [Parameter(Mandatory=$true)] + [string] + $path + ) + + { Invoke-Docker -Command build -Params @( + '--pull' + '--quiet' + '-t' + "$(Get-RepoName):${Name}" + $path + ) -SuppressHostOutput} | should not throw + } +} + +Describe "Linux Containers run PowerShell" -Tags 'Behavior', 'Linux' { + BeforeAll{ + $testContext = Get-TestContext -type Linux + } + AfterAll{ + # prune unused volumes + $null=Invoke-Docker -Command 'volume', 'prune' -Params '--force' -SuppressHostOutput + } + BeforeEach + { + Remove-Item $testContext.resolvedXmlPath -ErrorAction SilentlyContinue + Remove-Item $testContext.resolvedLogPath -ErrorAction SilentlyContinue + } + + it "Get PSVersion table from $(Get-RepoName):" -TestCases $script:linuxContainerTests -Skip:$script:skipLinux { + param( + [Parameter(Mandatory=$true)] + [string] + $name, + + [Parameter(Mandatory=$true)] + [string] + $path + ) + + Get-ContainerPowerShellVersion -TestContext $testContext -Name $Name -RepoName (Get-RepoName) | should be '6.0.0-beta' + } +} + +Describe "Windows Containers run PowerShell" -Tags 'Behavior', 'Windows' { + BeforeAll{ + $testContext = Get-TestContext -type Windows + } + BeforeEach + { + Remove-Item $testContext.resolvedXmlPath -ErrorAction SilentlyContinue + Remove-Item $testContext.resolvedLogPath -ErrorAction SilentlyContinue + } + + it "Get PSVersion table from $(Get-RepoName):" -TestCases $script:windowsContainerTests -skip:$script:skipWindows { + param( + [Parameter(Mandatory=$true)] + [string] + $name, + + [Parameter(Mandatory=$true)] + [string] + $path + ) + + Get-ContainerPowerShellVersion -TestContext $testContext -Name $Name -RepoName (Get-RepoName) | should be '6.0.0-beta' + } +} diff --git a/docker/tests/containerTestCommon.psm1 b/docker/tests/containerTestCommon.psm1 new file mode 100644 index 0000000000..2286a5dc23 --- /dev/null +++ b/docker/tests/containerTestCommon.psm1 @@ -0,0 +1,192 @@ +$script:forcePull = $true +# Get docker Engine OS +function Get-DockerEngineOs +{ + docker info --format '{{ .OperatingSystem }}' +} + +# Call Docker with appropriate result checksfunction Invoke-Docker +function Invoke-Docker +{ + param( + [Parameter(Mandatory=$true)] + [string[]] + $Command, + [ValidateSet("error","warning",'ignore')] + $FailureAction = 'error', + + [Parameter(Mandatory=$true)] + [string[]] + $Params, + + [switch] + $PassThru, + [switch] + $SuppressHostOutput + ) + + $ErrorActionPreference = 'Continue' + + # Log how we are running docker for troubleshooting issues + Write-Verbose "Running docker $command $params" -Verbose + if($SuppressHostOutput.IsPresent) + { + $result = docker $command $params 2>&1 + } + else + { + &'docker' $command $params 2>&1 | Tee-Object -Variable result -ErrorAction SilentlyContinue | Out-String -Stream -ErrorAction SilentlyContinue | Write-Host -ErrorAction SilentlyContinue + } + + $dockerExitCode = $LASTEXITCODE + if($PassThru.IsPresent) + { + Write-Verbose "passing through docker result$($result.length)..." -Verbose + return $result + } + elseif($dockerExitCode -ne 0 -and $FailureAction -eq 'error') + { + Write-Error "docker $command failed with: $result" -ErrorAction Stop + return $false + } + elseif($dockerExitCode -ne 0 -and $FailureAction -eq 'warning') + { + Write-Warning "docker $command failed with: $result" + return $false + } + elseif($dockerExitCode -ne 0) + { + return $false + } + + return $true +} + +# Return a list of Linux Container Test Cases +function Get-LinuxContainer +{ + foreach($os in 'centos7','opensuse42.1','ubuntu14.04','ubuntu16.04') + { + Write-Output @{ + Name = $os + Path = "$psscriptroot/../release/$os" + } + } + +} + +# Return a list of Windows Container Test Cases +function Get-WindowsContainer +{ + foreach($os in 'windowsservercore','nanoserver') + { + Write-Output @{ + Name = $os + Path = "$psscriptroot/../release/$os" + } + } +} + + +$script:repoName = 'microsoft/powershell' +function Get-RepoName +{ + return $script:repoName +} + +function Set-RepoName +{ + param([string]$RepoName) + + $script:repoName = $RepoName + $script:forcePull = $false +} + +function Test-SkipWindows +{ + [bool] $canRunWindows = (Get-DockerEngineOs) -like 'Windows*' + return ($IsLinux -or $IsOSX -or !$canRunWindows) +} + +function Test-SkipLinux +{ + return !((Get-DockerEngineOs) -like 'Alpine Linux*') +} + +function Get-TestContext +{ + param( + [ValidateSet('Linux','Windows','macOS')] + [string]$Type + ) + + $resultFileName = 'results.xml' + $logFileName = 'results.log' + $containerTestDrive = '/test' + + # Return a windows context if the Context in Windows *AND* + # the current system is windows, otherwise Join-path will fail. + if($Type -eq 'Windows' -and $IsWindows) + { + $ContainerTestDrive = 'C:\test' + } + $resolvedTestDrive = (Resolve-Path "Testdrive:\").providerPath + + return @{ + ResolvedTestDrive = $resolvedTestDrive + ResolvedXmlPath = Join-Path $resolvedTestDrive -ChildPath $resultFileName + ResolvedLogPath = Join-Path $resolvedTestDrive -ChildPath $logFileName + ContainerTestDrive = $ContainerTestDrive + ContainerXmlPath = Join-Path $containerTestDrive -ChildPath $resultFileName + ContainerLogPath = Join-Path $containerTestDrive -ChildPath $logFileName + Type = $Type + ForcePull = $script:forcePull + } +} + +function Get-ContainerPowerShellVersion +{ + param( + [HashTable] $TestContext, + [string] $RepoName, + [string] $Name + ) + + $imageTag = "${script:repoName}:${Name}" + + if($TestContext.ForcePull) + { + $null=Invoke-Docker -Command 'image', 'pull' -Params $imageTag -SuppressHostOutput + } + + $runParams = @() + $localVolumeName = $testContext.resolvedTestDrive + $runParams += '--rm' + if($TestContext.Type -ne 'Windows' -and $isWindows) + { + # use a container volume on windows because host volumes are not automatic + $volumeName = "test-volume-" + (Get-Random -Minimum 100 -Maximum 999) + + # using alpine because it's tiny + $null=Invoke-Docker -Command create -Params '-v', '/test', '--name', $volumeName, 'alpine' -SuppressHostOutput + $runParams += '--volumes-from' + $runParams += $volumeName + } + else { + $runParams += '-v' + $runParams += "${localVolumeName}:$($testContext.containerTestDrive)" + } + + $runParams += $imageTag + $runParams += 'powershell' + $runParams += '-c' + $runParams += ('$PSVersionTable.PSVersion.ToString() | out-string | out-file -encoding ascii -FilePath '+$testContext.containerLogPath) + + $null = Invoke-Docker -Command run -Params $runParams -SuppressHostOutput + if($TestContext.Type -ne 'Windows' -and $isWindows) + { + $null = Invoke-Docker -Command cp -Params "${volumeName}:$($testContext.containerLogPath)", $TestContext.ResolvedLogPath + $null = Invoke-Docker -Command container, rm -Params $volumeName, '--force' -SuppressHostOutput + } + return (Get-Content -Encoding Ascii $testContext.resolvedLogPath)[0] +}