Compare commits
2
Commits
4bbde1dfe2
...
ac62c5476d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac62c5476d | ||
|
|
ddbc3fa48e |
No files matched your search
@@ -0,0 +1,12 @@
|
||||
# Scoop Medelexis AG - Intern
|
||||
|
||||
Damit die PowerShell-Scripte ausgeführt werden können, muss im Terminal-Fenster zuerst `Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass` eingegeben und ausgeführt werden.
|
||||
|
||||
**Scripts:**
|
||||
|
||||
* Install -> installiert Scoop und fügt die Buckets extras und medelexis hinzu
|
||||
* update-bucket -> Migriert bestehende Buckets und Pakete auf medelexis *(kann mehrfach ausgeführt werden)
|
||||
(ohne -Apply wird nur ein Probelauf durchgeführt. Wenn das Update angewendet werden soll, muss "update-bucket.ps1 -Apply" verwendet werden.)*
|
||||
* setup-auto-update -> Richtet eine tägliche Scoop-Update-Aufgabe ein, repariert oder entfernt sie.
|
||||
|
||||
Andere Scripts sind System-Scripts und nicht für manuelle Ausführung gedacht.
|
||||
+4
-4
@@ -29,12 +29,12 @@ else {
|
||||
}
|
||||
|
||||
# 3. BUCKET CHECKS
|
||||
if ($bucketList -match "elexis") {
|
||||
Write-Host "elexis Bucket ist bereits vorhanden." -ForegroundColor White
|
||||
if ($bucketList -match '(?m)^\s*medelexis\s') {
|
||||
Write-Host "Medelexis-Bucket ist bereits vorhanden." -ForegroundColor White
|
||||
}
|
||||
else {
|
||||
scoop bucket add elexis https://gitea.medelexis.ch/public/scoop
|
||||
Write-Host "elexis Bucket hinzugefügt." -ForegroundColor Green
|
||||
scoop bucket add medelexis https://gitea.medelexis.ch/public/scoop
|
||||
Write-Host "Medelexis-Bucket hinzugefügt." -ForegroundColor Green
|
||||
}
|
||||
|
||||
if ($bucketList -match "extras") {
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
#requires -Version 5.1
|
||||
# Isolated behavioural tests: no real downloads, Scoop updates or scheduled tasks.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$projectRoot = Split-Path $PSScriptRoot -Parent
|
||||
$fixtureRoot = Join-Path $PSScriptRoot ('.auto-update-test-' + [guid]::NewGuid())
|
||||
$oldScoop = $env:SCOOP
|
||||
$oldPath = $env:PATH
|
||||
$oldFixture = $env:SCOOP_AUTO_UPDATE_TEST_ROOT
|
||||
$oldFailure = $env:SCOOP_AUTO_UPDATE_TEST_FAILURE
|
||||
|
||||
function Assert-True($Condition, [string] $Message) {
|
||||
if (-not $Condition) { throw $Message }
|
||||
}
|
||||
function Assert-HiddenTask($Task, [string] $Runner, [string] $ScoopRoot) {
|
||||
Assert-True ($Task.TaskName -eq 'Medelexis AG - Scoop AutoUpdate') 'Unexpected task name.'
|
||||
$description = 'T' + [char]0x00e4 + 'gliche Aktualisierung der installierten Elemente (Elexis ausgeschlossen)'
|
||||
Assert-True ($Task.Description -ceq $description) 'Unexpected task description.'
|
||||
$launcher = Join-Path (Split-Path $Runner -Parent) 'auto-update-hidden.exe'
|
||||
Assert-True ($Task.Action.Execute -eq $launcher -and (Test-Path -LiteralPath $launcher)) 'Task must use the GUI launcher.'
|
||||
Assert-True ($Task.Action.Argument -eq ('"{0}" "{1}"' -f $Runner, $ScoopRoot)) 'Expected quoted runner and Scoop root.'
|
||||
}
|
||||
|
||||
# These stand-ins capture scheduling settings without changing Windows.
|
||||
function New-ScheduledTaskAction { param($Execute, $Argument) [pscustomobject]$PSBoundParameters }
|
||||
function New-ScheduledTaskTrigger { param([switch]$Daily, $At) [pscustomobject]$PSBoundParameters }
|
||||
function New-ScheduledTaskPrincipal { param($UserId, $LogonType, $RunLevel) [pscustomobject]$PSBoundParameters }
|
||||
function New-ScheduledTaskSettingsSet {
|
||||
param([switch]$StartWhenAvailable, [switch]$RunOnlyIfNetworkAvailable,
|
||||
[switch]$AllowStartIfOnBatteries, [switch]$DontStopIfGoingOnBatteries,
|
||||
$MultipleInstances, $ExecutionTimeLimit)
|
||||
[pscustomobject]$PSBoundParameters
|
||||
}
|
||||
function Register-ScheduledTask {
|
||||
param($TaskName, $Action, $Trigger, $Principal, $Settings, [switch]$Force, $Description)
|
||||
$global:AutoUpdateTestTask = [pscustomobject]$PSBoundParameters
|
||||
$global:AutoUpdateTestTasks[$TaskName] = $global:AutoUpdateTestTask
|
||||
}
|
||||
function Get-ScheduledTask {
|
||||
param($TaskName, $ErrorAction)
|
||||
if ($global:AutoUpdateTestTasks.ContainsKey($TaskName)) { $global:AutoUpdateTestTasks[$TaskName] }
|
||||
}
|
||||
function Unregister-ScheduledTask {
|
||||
param($TaskName, [switch]$Confirm)
|
||||
$expected = 'Medelexis-Scoop-AutoUpdate-' + [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
|
||||
Assert-True ($TaskName -in @($expected, 'Medelexis AG - Scoop AutoUpdate') -and -not $Confirm) 'Only remove the matching auto-update task.'
|
||||
$global:AutoUpdateTestRemovedTask = $TaskName
|
||||
$global:AutoUpdateTestTasks.Remove($TaskName)
|
||||
}
|
||||
function Stop-ScheduledTask {
|
||||
param($TaskName)
|
||||
$global:AutoUpdateTestStoppedTask = $TaskName
|
||||
$global:AutoUpdateTestTasks[$TaskName].State = 'Ready'
|
||||
}
|
||||
function Read-Host {
|
||||
param($Prompt)
|
||||
$global:AutoUpdateTestPrompts.Add($Prompt)
|
||||
$global:AutoUpdateTestAnswers.Dequeue()
|
||||
}
|
||||
function Invoke-WebRequest {
|
||||
param($Uri, $OutFile, [switch]$UseBasicParsing)
|
||||
$global:AutoUpdateTestDownloads++
|
||||
Assert-True ($Uri -in @('https://example.test/scoop/raw/branch/master/scripts/auto-update.ps1',
|
||||
'https://gitea.medelexis.ch/public/scoop/raw/branch/master/scripts/auto-update.ps1')) 'Unexpected download URL.'
|
||||
if ($global:AutoUpdateTestInvalidDownload) {
|
||||
'This is not the setup script.' | Set-Content -LiteralPath $OutFile
|
||||
} else {
|
||||
@'
|
||||
param([string] $ScoopRoot)
|
||||
throw 'The downloaded runner must not execute during setup.'
|
||||
'@ | Set-Content -LiteralPath $OutFile
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
# Spaces in the installation path exercise the scheduled command's quoting.
|
||||
$scoopRoot = Join-Path $fixtureRoot ('scoop with spaces ' + [char]0x00e4)
|
||||
$shims = Join-Path $scoopRoot 'shims'
|
||||
New-Item -ItemType Directory -Path $shims -Force | Out-Null
|
||||
$scriptPath = Join-Path $fixtureRoot 'auto-update.ps1'
|
||||
Copy-Item -LiteralPath (Join-Path $projectRoot 'scripts\auto-update.ps1') -Destination $scriptPath
|
||||
$env:SCOOP_AUTO_UPDATE_TEST_ROOT = $fixtureRoot
|
||||
$commandLog = Join-Path $fixtureRoot 'commands.log'
|
||||
@'
|
||||
param([Parameter(ValueFromRemainingArguments = $true)][string[]] $ScoopArguments)
|
||||
Add-Content -LiteralPath (Join-Path $env:SCOOP_AUTO_UPDATE_TEST_ROOT 'commands.log') -Value ($ScoopArguments -join ' ')
|
||||
if ($env:SCOOP_AUTO_UPDATE_TEST_FAILURE -eq ($ScoopArguments -join ' ')) { exit 1 }
|
||||
if ($ScoopArguments[0] -eq 'list') {
|
||||
[pscustomobject]@{ Name = 'elexis'; Info = '' }
|
||||
[pscustomobject]@{ Name = 'Elexis-test'; Info = 'Held package' }
|
||||
[pscustomobject]@{ Name = 'myelexis-cli'; Info = '' }
|
||||
[pscustomobject]@{ Name = 'git'; Info = '' }
|
||||
[pscustomobject]@{ Name = 'elexis-global'; Info = 'Global install' }
|
||||
[pscustomobject]@{ Name = 'elexis-broken'; Info = 'Install failed' }
|
||||
}
|
||||
exit 0
|
||||
'@ | Set-Content -LiteralPath (Join-Path $shims 'scoop.ps1') -Encoding UTF8
|
||||
|
||||
& $scriptPath -ScoopRoot $scoopRoot
|
||||
Assert-True ($LASTEXITCODE -eq 0) 'Expected successful update.'
|
||||
Assert-True (((Get-Content $commandLog) -join '|') -eq 'list|hold elexis|hold Elexis-test|update|update *') 'Expected only local elexis* held before updates.'
|
||||
Assert-True (Test-Path (Join-Path $fixtureRoot 'auto-update.log')) 'Expected update log.'
|
||||
|
||||
foreach ($failure in @('list', 'hold elexis', 'update', 'update *')) {
|
||||
Remove-Item -LiteralPath $commandLog
|
||||
$env:SCOOP_AUTO_UPDATE_TEST_FAILURE = $failure
|
||||
# Expected errors are logged; do not let test ErrorActionPreference terminate the caller.
|
||||
$ErrorActionPreference = 'Continue'
|
||||
& $scriptPath -ScoopRoot $scoopRoot 2>$null
|
||||
$result = $LASTEXITCODE
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Assert-True ($result -eq 1) "Expected failure status for $failure."
|
||||
$commands = @(Get-Content $commandLog)
|
||||
Assert-True ($commands[-1] -eq $failure) "Must abort immediately after $failure."
|
||||
}
|
||||
# Test all entry points without migrating buckets or changing real tasks.
|
||||
$tokens = $null
|
||||
$errors = $null
|
||||
$bucketAst = [Management.Automation.Language.Parser]::ParseFile((Join-Path $projectRoot 'scripts\update-bucket.ps1'), [ref]$tokens, [ref]$errors)
|
||||
Assert-True ($errors.Count -eq 0) 'Invalid bucket script syntax.'
|
||||
$setupStatements = @($bucketAst.EndBlock.Statements)
|
||||
$setupStart = 0
|
||||
while ($setupStart -lt $setupStatements.Count -and -not $setupStatements[$setupStart].Extent.Text.StartsWith('$userId =')) { $setupStart++ }
|
||||
Assert-True ($setupStart -lt $setupStatements.Count) 'Setup block missing in bucket migration.'
|
||||
$optInBlock = [scriptblock]::Create((($setupStatements[$setupStart..($setupStatements.Count - 1)] | ForEach-Object { $_.Extent.Text }) -join "`n"))
|
||||
$repository = 'https://example.test/scoop'
|
||||
Remove-Item -LiteralPath $commandLog
|
||||
$global:AutoUpdateTestAnswers = [Collections.Generic.Queue[string]]::new()
|
||||
$global:AutoUpdateTestPrompts = [Collections.Generic.List[string]]::new()
|
||||
$global:AutoUpdateTestTasks = @{}
|
||||
$global:AutoUpdateTestDownloads = 0
|
||||
$downloadDirectory = Join-Path $scoopRoot 'scripts\medelexis'
|
||||
$downloadedPath = Join-Path $downloadDirectory 'auto-update.ps1'
|
||||
$launcherPath = Join-Path $downloadDirectory 'auto-update-hidden.exe'
|
||||
$taskName = 'Medelexis AG - Scoop AutoUpdate'
|
||||
$legacyName = 'Medelexis-Scoop-AutoUpdate-' + [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
|
||||
$setupEntries = @($optInBlock, (Join-Path $projectRoot 'scripts\setup-auto-update.ps1'))
|
||||
foreach ($entry in $setupEntries) {
|
||||
$global:AutoUpdateTestPrompts.Clear()
|
||||
$global:AutoUpdateTestAnswers.Enqueue('n')
|
||||
& $entry -ScoopRoot $scoopRoot
|
||||
Assert-True ($global:AutoUpdateTestPrompts.Count -eq 1 -and $global:AutoUpdateTestPrompts[0] -eq 'Scoop-Auto-Update einschalten? [y/n]') 'Missing task must offer normal setup.'
|
||||
Assert-True ($global:AutoUpdateTestTasks.Count -eq 0) 'Declining initial setup must not register a task.'
|
||||
|
||||
$global:AutoUpdateTestInvalidDownload = $false
|
||||
$global:AutoUpdateTestAnswers.Enqueue('invalid')
|
||||
$global:AutoUpdateTestAnswers.Enqueue('Y')
|
||||
& $entry -ScoopRoot $scoopRoot
|
||||
$task = $global:AutoUpdateTestTasks[$taskName]
|
||||
Assert-HiddenTask $task $downloadedPath $scoopRoot
|
||||
Assert-True ($task.Trigger.Daily -and $task.Trigger.At -eq '03:00' -and $task.Settings.StartWhenAvailable) 'Expected daily 03:00 with catch-up.'
|
||||
Assert-True ($task.Settings.RunOnlyIfNetworkAvailable -and $task.Settings.MultipleInstances -eq 'IgnoreNew') 'Expected network and overlap settings.'
|
||||
Assert-True ($task.Principal.LogonType -eq 'Interactive' -and $task.Principal.RunLevel -eq 'Limited') 'Expected normal user session.'
|
||||
Assert-True (-not (Test-Path $commandLog)) 'Setup must not execute Scoop or migrations.'
|
||||
|
||||
# No/no must leave task, runner and launcher byte-for-byte unchanged.
|
||||
$downloads = $global:AutoUpdateTestDownloads
|
||||
$runnerBefore = (Get-FileHash -LiteralPath $downloadedPath).Hash
|
||||
$launcherBefore = (Get-FileHash -LiteralPath $launcherPath).Hash
|
||||
$global:AutoUpdateTestPrompts.Clear()
|
||||
$global:AutoUpdateTestAnswers.Enqueue('n')
|
||||
$global:AutoUpdateTestAnswers.Enqueue('n')
|
||||
& $entry -ScoopRoot $scoopRoot
|
||||
Assert-True ($global:AutoUpdateTestPrompts.Count -eq 2 -and $global:AutoUpdateTestPrompts[0] -like '*reparieren*' -and $global:AutoUpdateTestPrompts[1] -like '*entfernen*') 'Expected repair then removal questions.'
|
||||
Assert-True ($global:AutoUpdateTestTasks[$taskName] -eq $task -and $global:AutoUpdateTestDownloads -eq $downloads) 'No/no must preserve the task and avoid downloading.'
|
||||
Assert-True ((Get-FileHash -LiteralPath $downloadedPath).Hash -eq $runnerBefore -and (Get-FileHash -LiteralPath $launcherPath).Hash -eq $launcherBefore) 'No/no must preserve files.'
|
||||
|
||||
# Repair downloads and replaces the existing task, without duplicating it.
|
||||
$global:AutoUpdateTestPrompts.Clear()
|
||||
$global:AutoUpdateTestAnswers.Enqueue('y')
|
||||
& $entry -ScoopRoot $scoopRoot
|
||||
Assert-True ($global:AutoUpdateTestPrompts.Count -eq 1 -and $global:AutoUpdateTestPrompts[0] -like '*reparieren*') 'Repair must ask only the repair question.'
|
||||
Assert-True ($global:AutoUpdateTestDownloads -eq $downloads + 1 -and $global:AutoUpdateTestTasks.Count -eq 1) 'Repair must download and replace the existing task.'
|
||||
Assert-HiddenTask $global:AutoUpdateTestTasks[$taskName] $downloadedPath $scoopRoot
|
||||
|
||||
# Failed repair must retain the prior runner and task.
|
||||
$task = $global:AutoUpdateTestTasks[$taskName]
|
||||
$global:AutoUpdateTestInvalidDownload = $true
|
||||
$global:AutoUpdateTestAnswers.Enqueue('y')
|
||||
$rejected = $false
|
||||
try { & $entry -ScoopRoot $scoopRoot } catch { $rejected = $true }
|
||||
Assert-True $rejected 'Invalid download must be rejected.'
|
||||
Assert-True ($global:AutoUpdateTestTasks[$taskName] -eq $task -and (Get-FileHash -LiteralPath $downloadedPath).Hash -eq $runnerBefore) 'Failed repair must preserve the existing runner and task.'
|
||||
Assert-True (@(Get-ChildItem $downloadDirectory -Filter '*.download').Count -eq 0) 'Temporary downloads must be removed.'
|
||||
$global:AutoUpdateTestInvalidDownload = $false
|
||||
|
||||
# Also recognize the earlier task name, and remove only managed files.
|
||||
$global:AutoUpdateTestTasks.Clear()
|
||||
$global:AutoUpdateTestTasks[$legacyName] = [pscustomobject]@{ TaskName = $legacyName; State = 'Running' }
|
||||
Set-Content -LiteralPath (Join-Path $downloadDirectory 'auto-update.log') -Value 'old log'
|
||||
Set-Content -LiteralPath (Join-Path $downloadDirectory 'unrelated.txt') -Value 'keep'
|
||||
$downloads = $global:AutoUpdateTestDownloads
|
||||
$global:AutoUpdateTestAnswers.Enqueue('n')
|
||||
$global:AutoUpdateTestAnswers.Enqueue('y')
|
||||
& $entry -ScoopRoot $scoopRoot
|
||||
Assert-True ($global:AutoUpdateTestTasks.Count -eq 0 -and $global:AutoUpdateTestStoppedTask -eq $legacyName) 'Remove must stop and unregister the existing legacy task.'
|
||||
Assert-True (-not (Test-Path $downloadedPath) -and -not (Test-Path $launcherPath) -and -not (Test-Path (Join-Path $downloadDirectory 'auto-update.log'))) 'Remove must delete the runner, launcher and log.'
|
||||
Assert-True ((Test-Path (Join-Path $downloadDirectory 'unrelated.txt')) -and $global:AutoUpdateTestDownloads -eq $downloads) 'Remove must preserve unrelated files and avoid downloading.'
|
||||
|
||||
# Repair migrates the legacy name to the requested task name.
|
||||
$global:AutoUpdateTestTasks[$legacyName] = [pscustomobject]@{ TaskName = $legacyName; State = 'Ready' }
|
||||
$global:AutoUpdateTestAnswers.Enqueue('y')
|
||||
& $entry -ScoopRoot $scoopRoot
|
||||
Assert-True ($global:AutoUpdateTestTasks.Count -eq 1 -and $global:AutoUpdateTestTasks.ContainsKey($taskName)) 'Repair must migrate the legacy task.'
|
||||
# Removal of the current name must offer the same behaviour.
|
||||
$global:AutoUpdateTestAnswers.Enqueue('n')
|
||||
$global:AutoUpdateTestAnswers.Enqueue('y')
|
||||
& $entry -ScoopRoot $scoopRoot
|
||||
Assert-True ($global:AutoUpdateTestTasks.Count -eq 0 -and -not (Test-Path $downloadedPath)) 'Remove must also handle the current task name.'
|
||||
}
|
||||
# Prepare one local launcher for the real hidden-process smoke test below.
|
||||
$global:AutoUpdateTestAnswers.Enqueue('y')
|
||||
& (Join-Path $projectRoot 'scripts\setup-auto-update.ps1') -ScoopRoot $scoopRoot
|
||||
$task = $global:AutoUpdateTestTasks[$taskName]
|
||||
|
||||
# Run only a harmless local fixture through the actual GUI launcher. No Scoop
|
||||
# or scheduler calls: verify quoting, hidden child window and exit propagation.
|
||||
@'
|
||||
param([string] $ScoopRoot)
|
||||
Add-Type -TypeDefinition @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public class AutoUpdateWindowTest {
|
||||
[DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow();
|
||||
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr handle);
|
||||
}
|
||||
"@
|
||||
$visible = [AutoUpdateWindowTest]::IsWindowVisible([AutoUpdateWindowTest]::GetConsoleWindow())
|
||||
Set-Content -LiteralPath (Join-Path $ScoopRoot 'hidden-test.txt') -Value ([string]$visible)
|
||||
exit 23
|
||||
'@ | Set-Content -LiteralPath $downloadedPath -Encoding UTF8
|
||||
$process = Start-Process -FilePath $task.Action.Execute -ArgumentList $task.Action.Argument -WindowStyle Hidden -PassThru
|
||||
if (-not $process.WaitForExit(20000)) {
|
||||
$process.Kill()
|
||||
throw 'Hidden launcher did not finish within 20 seconds.'
|
||||
}
|
||||
Assert-True ($process.ExitCode -eq 23) 'Launcher must forward the runner exit code.'
|
||||
Assert-True ((Get-Content -LiteralPath (Join-Path $scoopRoot 'hidden-test.txt')) -eq 'False') 'Runner must have no visible console window.'
|
||||
Write-Host 'PASS: install, repair, no/no, removal, legacy tasks, hidden launcher, schedule, hold filtering and failures.'
|
||||
} finally {
|
||||
$env:SCOOP = $oldScoop
|
||||
$env:PATH = $oldPath
|
||||
$env:SCOOP_AUTO_UPDATE_TEST_ROOT = $oldFixture
|
||||
$env:SCOOP_AUTO_UPDATE_TEST_FAILURE = $oldFailure
|
||||
Remove-Variable AutoUpdateTestTask, AutoUpdateTestAnswers, AutoUpdateTestInvalidDownload, AutoUpdateTestRemovedTask, AutoUpdateTestTasks, AutoUpdateTestDownloads, AutoUpdateTestPrompts, AutoUpdateTestStoppedTask -Scope Global -ErrorAction SilentlyContinue
|
||||
# Delete only this test's unique directory, after checking its absolute parent.
|
||||
if ((Test-Path -LiteralPath $fixtureRoot) -and
|
||||
[IO.Path]::GetDirectoryName([IO.Path]::GetFullPath($fixtureRoot)) -eq [IO.Path]::GetFullPath($PSScriptRoot) -and
|
||||
[IO.Path]::GetFileName($fixtureRoot).StartsWith('.auto-update-test-')) {
|
||||
Remove-Item -LiteralPath $fixtureRoot -Recurse -Force
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user