Release v0.2.1: support remote input, safe updates and high-DPI windows
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
param([string]$Executable = (Join-Path $PSScriptRoot '../build/KSwitcher.exe'), [switch]$Network)
|
||||
$ErrorActionPreference='Stop'
|
||||
. (Join-Path $PSScriptRoot '../resources/update.ps1') -Library
|
||||
$script:checks=0
|
||||
function Assert($Value,[string]$Name) { if (!$Value) { throw $Name }; ++$script:checks }
|
||||
function Reject([scriptblock]$Action,[string]$Name) { $rejected=$false; try { & $Action } catch { $rejected=$true }; Assert $rejected $Name }
|
||||
$root=Join-Path ([IO.Path]::GetTempPath()) ('KSwitcher-update-tests-'+[guid]::NewGuid().ToString('N'))
|
||||
[IO.Directory]::CreateDirectory($root) | Out-Null
|
||||
try {
|
||||
Assert ((Get-StableVersion 'v0.10.0') -gt (Get-StableVersion 'v0.2.9')) 'numeric versions'
|
||||
Assert ($null -eq (Get-StableVersion 'v1.0.0-beta')) 'prerelease rejected'
|
||||
Assert ($null -eq (Get-StableVersion 'v1.0.0;whoami')) 'invalid version rejected'
|
||||
$assets=@(
|
||||
@{name='KSwitcher-win-x64.zip';browser_download_url='https://gitea.hrynco.com/hrynco/hrynco-kswitcher/releases/download/v0.2.1/KSwitcher-win-x64.zip'},
|
||||
@{name='SHA256SUMS.txt';browser_download_url='https://gitea.hrynco.com/hrynco/hrynco-kswitcher/releases/download/v0.2.1/SHA256SUMS.txt'}
|
||||
)
|
||||
$release=@{draft=$false;prerelease=$false;tag_name='v0.2.1';assets=$assets}
|
||||
Assert ((Select-Release @($release) ([version]'0.2.0')).version -eq 'v0.2.1') 'newer release'
|
||||
Assert ($null -eq (Select-Release @($release) ([version]'0.2.1'))) 'same version'
|
||||
Assert ($null -eq (Select-Release @($release) ([version]'0.3.0'))) 'no downgrade'
|
||||
$draft=@{draft=$true;prerelease=$false;tag_name='v9.0.0';assets=$assets}
|
||||
Assert ((Select-Release @($draft,$release) ([version]'0.2.0')).version -eq 'v0.2.1') 'draft ignored'
|
||||
Reject { Select-Release @(@{draft=$false;prerelease=$false;tag_name='v2.0.0';assets=@()}) ([version]'0.2.0') } 'incomplete release rejected'
|
||||
foreach ($url in @('http://gitea.hrynco.com/hrynco/hrynco-kswitcher/releases/download/v1/a','https://evil.example/a','https://gitea.hrynco.com/other/a','https://gitea.hrynco.com:8443/hrynco/hrynco-kswitcher/releases/download/v1/a')) {
|
||||
Reject { Assert-ReleaseUrl $url } 'untrusted URL rejected'
|
||||
}
|
||||
$source=Join-Path $root 'source'; [IO.Directory]::CreateDirectory($source) | Out-Null
|
||||
Copy-Item -LiteralPath $Executable -Destination (Join-Path $source 'KSwitcher.exe')
|
||||
foreach ($name in @('LICENSE','json-LICENSE.txt','README.md')) { [IO.File]::WriteAllText((Join-Path $source $name),'fixture') }
|
||||
[IO.Directory]::CreateDirectory((Join-Path $source 'dictionaries')) | Out-Null
|
||||
[IO.File]::WriteAllText((Join-Path $source 'dictionaries/en.txt'),'new dictionary')
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
$archive=Join-Path $root 'release.zip'
|
||||
[IO.Compression.ZipFile]::CreateFromDirectory($source,$archive)
|
||||
$sum=Join-Path $root 'SHA256SUMS.txt'
|
||||
((Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash+' KSwitcher-win-x64.zip') | Set-Content -LiteralPath $sum
|
||||
Assert-Checksum $archive $sum; ++$script:checks
|
||||
$stage=Join-Path $root 'stage'
|
||||
Expand-Release $archive $stage ([version]'0.2.1'); ++$script:checks
|
||||
Reject { Expand-Release $archive (Join-Path $root 'wrong-version') ([version]'9.0.0') } 'version mismatch rejected'
|
||||
('0'*64+' KSwitcher-win-x64.zip') | Set-Content -LiteralPath $sum
|
||||
Reject { Assert-Checksum $archive $sum } 'corrupt package rejected'
|
||||
$bad=Join-Path $root 'bad.zip'
|
||||
$z=[IO.Compression.ZipFile]::Open($bad,[IO.Compression.ZipArchiveMode]::Create)
|
||||
$null=$z.CreateEntry('../escape.exe'); $z.Dispose()
|
||||
Reject { Expand-Release $bad (Join-Path $root 'badstage') ([version]'0.2.1') } 'zip traversal rejected'
|
||||
$target=Join-Path $root 'install'; $backup=Join-Path $root 'backup'
|
||||
[IO.Directory]::CreateDirectory((Join-Path $target 'data')) | Out-Null
|
||||
[IO.Directory]::CreateDirectory((Join-Path $target 'dictionaries')) | Out-Null
|
||||
[IO.File]::WriteAllText((Join-Path $target 'data/settings.json'),'personal settings')
|
||||
[IO.File]::WriteAllText((Join-Path $target 'dictionaries/en.txt'),'personal dictionary')
|
||||
[IO.File]::WriteAllText((Join-Path $target 'KSwitcher.exe'),'old binary fixture')
|
||||
$changed=[Collections.Generic.List[string]]::new()
|
||||
Install-Files $stage $target $backup $changed
|
||||
Assert ((Get-FileHash -LiteralPath (Join-Path $target 'KSwitcher.exe')).Hash -eq (Get-FileHash -LiteralPath $Executable).Hash) 'replacement installed'
|
||||
Assert ([IO.File]::ReadAllText((Join-Path $target 'data/settings.json')) -eq 'personal settings') 'settings preserved'
|
||||
Assert ([IO.File]::ReadAllText((Join-Path $target 'dictionaries/en.txt')) -eq 'personal dictionary') 'dictionary preserved'
|
||||
Undo-Files $target $backup $changed
|
||||
Assert ([IO.File]::ReadAllText((Join-Path $target 'KSwitcher.exe')) -eq 'old binary fixture') 'rollback restores original'
|
||||
Assert (!(Test-Path -LiteralPath (Join-Path $target 'README.md'))) 'rollback removes newly introduced files'
|
||||
# Fail after the original exe has moved to backup, as if the staged file vanished.
|
||||
$stage2=Join-Path $root 'stage2'; [IO.Directory]::CreateDirectory($stage2) | Out-Null
|
||||
[IO.File]::WriteAllText((Join-Path $stage2 'KSwitcher.exe'),'new binary fixture')
|
||||
$locked=[IO.File]::Open((Join-Path $stage2 'KSwitcher.exe'),[IO.FileMode]::Open,[IO.FileAccess]::Read,[IO.FileShare]::None)
|
||||
$changed2=[Collections.Generic.List[string]]::new()
|
||||
try { Reject { Install-Files $stage2 $target $backup $changed2 } 'locked staged file fails safely' } finally { $locked.Dispose() }
|
||||
Undo-Files $target $backup $changed2
|
||||
Assert ([IO.File]::ReadAllText((Join-Path $target 'KSwitcher.exe')) -eq 'old binary fixture') 'partial install rollback'
|
||||
if ($Network) {
|
||||
$metadata=Join-Path $root 'live-releases.json'
|
||||
Receive-File 'https://gitea.hrynco.com/api/v1/repos/hrynco/hrynco-kswitcher/releases?limit=100' $metadata 2MB
|
||||
$live=Select-Release (Get-Content -LiteralPath $metadata -Raw | ConvertFrom-Json) ([version]'0.0.0')
|
||||
Assert ($null -ne $live) 'live repository exposes a complete stable release'
|
||||
$liveZip=Join-Path $root 'live.zip'; $liveSum=Join-Path $root 'live-sums.txt'
|
||||
Receive-File $live.zip $liveZip 50MB
|
||||
Receive-File $live.checksum $liveSum 64KB
|
||||
Assert-Checksum $liveZip $liveSum; ++$script:checks
|
||||
Expand-Release $liveZip (Join-Path $root 'live-stage') (Get-StableVersion $live.version); ++$script:checks
|
||||
Reject { Receive-File 'https://gitea.hrynco.com/api/v1/repos/hrynco/kswitcher-updater-missing-test-repository' (Join-Path $root 'missing') 2MB } 'server failure reported'
|
||||
Write-Output "Downloaded and validated $($live.version) in a disposable test directory; no application was updated."
|
||||
}
|
||||
Write-Output "Passed $script:checks updater regression checks"
|
||||
} finally {
|
||||
if ([IO.Path]::GetDirectoryName($root) -eq [IO.Path]::GetTempPath().TrimEnd('\') -and (Split-Path -Leaf $root) -like 'KSwitcher-update-tests-*') {
|
||||
Remove-Item -LiteralPath $root -Recurse -Force
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user