| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- # Exercise the production NSIS directory transaction with private installation directories.
- param(
- [Parameter(Mandatory)][string]$Makensis,
- [Parameter(Mandatory)][string]$SevenZip,
- [string]$FrameLibrary,
- [scriptblock]$SignExecutable
- )
- $ErrorActionPreference = 'Stop'
- $Makensis = [System.IO.Path]::GetFullPath($Makensis)
- $SevenZip = [System.IO.Path]::GetFullPath($SevenZip)
- $scratch = [System.IO.Directory]::CreateTempSubdirectory('dsh-directory-smoke-').FullName
- $fixture = Join-Path $PSScriptRoot '../tests/fixtures/installer-directory-smoke.nsi'
- function Invoke-Checked([string]$Executable, [string[]]$Arguments) {
- & $Executable @Arguments | Out-Host
- if ($LASTEXITCODE -ne 0) { throw "$Executable exited with $LASTEXITCODE" }
- }
- try {
- $payload = Join-Path $scratch 'payload'
- New-Item -ItemType Directory -Path $payload | Out-Null
- [System.IO.File]::WriteAllText((Join-Path $payload 'asset.txt'), 'new asset')
- $deepPayload = Join-Path $payload (('nested-' * 20) + '\asset-' + ('x' * 60) + '.txt')
- [IO.Directory]::CreateDirectory((Split-Path $deepPayload -Parent)) | Out-Null
- [IO.File]::WriteAllText($deepPayload, 'long path asset')
- $archive = Join-Path $scratch 'payload.7z'
- Invoke-Checked $SevenZip @('a', '-bd', '-t7z', $archive, "$payload/*")
- $brokenArchive = Join-Path $scratch 'broken.7z'
- [System.IO.File]::WriteAllText($brokenArchive, 'invalid archive')
- foreach ($mode in @('first', 'upgrade', 'locked', 'missing-stage', 'broken', 'cancelled')) {
- $caseRoot = Join-Path $scratch $mode
- $target = Join-Path $caseRoot 'Application'
- New-Item -ItemType Directory -Path $caseRoot | Out-Null
- if ($mode -ne 'first') {
- New-Item -ItemType Directory -Path $target | Out-Null
- [System.IO.File]::WriteAllText((Join-Path $target 'asset.txt'), 'old asset')
- [System.IO.File]::WriteAllText((Join-Path $target 'obsolete.txt'), 'old only')
- $oldDeep = Join-Path $target ([IO.Path]::GetRelativePath($payload, $deepPayload))
- [IO.Directory]::CreateDirectory((Split-Path $oldDeep -Parent)) | Out-Null
- [IO.File]::WriteAllText($oldDeep, 'old long path asset')
- }
- $probe = Join-Path $caseRoot 'probe.exe'
- $caseArchive = if ($mode -eq 'broken') { $brokenArchive } else { $archive }
- $compileArgs = @('/V2', "/DOUTPUT_FILE=$probe", "/DPAYLOAD_FILE=$caseArchive", "/DTARGET_DIR=$target", "/DDSH_SEVENZIP_PATH=$SevenZip")
- if ($FrameLibrary) { $compileArgs += "/DSOURCE_DLL=$FrameLibrary" }
- if ($mode -eq 'missing-stage') { $compileArgs += '/DMISSING_STAGE' }
- if ($mode -eq 'cancelled') { $compileArgs += '/DCANCELLED' }
- Invoke-Checked $Makensis ($compileArgs + $fixture)
- if ($null -ne $SignExecutable) { & $SignExecutable $probe }
- $handle = $null
- $process = $null
- try {
- if ($mode -eq 'locked') {
- $handle = [System.IO.File]::Open((Join-Path $target 'asset.txt'), 'Open', 'Read', 'Read')
- }
- $process = Start-Process -FilePath $probe -ArgumentList '/S' -WindowStyle Hidden -PassThru
- if (-not $process.WaitForExit(60000)) {
- $process.Kill($true)
- $process.WaitForExit()
- throw "Directory smoke $mode did not exit within 60 seconds"
- }
- $expectedExit = if ($mode -in @('first', 'upgrade')) { 0 } else { 2 }
- if ($process.ExitCode -ne $expectedExit) {
- throw "Directory smoke $mode exited with $($process.ExitCode), expected $expectedExit"
- }
- } finally {
- if ($null -ne $handle) { $handle.Dispose() }
- if ($null -ne $process) { $process.Dispose() }
- }
- $expectedAsset = if ($mode -in @('first', 'upgrade')) { 'new asset' } else { 'old asset' }
- if ([System.IO.File]::ReadAllText((Join-Path $target 'asset.txt')) -ne $expectedAsset) {
- throw "Directory smoke $mode changed the wrong version"
- }
- $expectObsolete = $mode -notin @('first', 'upgrade')
- if ((Test-Path -LiteralPath (Join-Path $target 'obsolete.txt')) -ne $expectObsolete) {
- throw "Directory smoke $mode did not preserve the expected old-only file state"
- }
- if (@(Get-ChildItem -LiteralPath $caseRoot -Directory | Where-Object Name -ne 'Application').Count -ne 0) {
- throw "Directory smoke $mode left transaction directories behind"
- }
- Write-Output "Directory replacement smoke passed: $mode"
- }
- } finally {
- $tempRoot = [System.IO.Path]::GetFullPath([System.IO.Path]::GetTempPath()).TrimEnd('\') + '\'
- $resolvedScratch = [System.IO.Path]::GetFullPath($scratch)
- if (-not $resolvedScratch.StartsWith($tempRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
- throw "Refusing cleanup outside the temporary root: $resolvedScratch"
- }
- Remove-Item -LiteralPath $resolvedScratch -Recurse -Force
- }
|