test(install): cubrir la ruta personalizada C:\Aduanasoft\CloudRestoreAS-win
Esa ruta es el peor caso posible y existe en produccion: la ruta por omision C:\Aduanasoft\CloudRestoreAS es PREFIJO DE CADENA de ella, asi que cualquier comparacion hecha con startsWith daria por iguales dos instalaciones distintas — y el resultado seria el fallo silencioso otra vez, actualizar una carpeta y arrancar la otra. El flujo ya la manejaba bien (Test-SamePath compara por igualdad exacta tras normalizar), pero nada lo probaba: la emulacion usaba declarada/otra-carpeta, nombres sin relacion entre si, que un startsWith mal puesto pasaria sin problema. - Escenario `sufijo` en emular-actualizacion-windows.ps1: instalacion en ...\CloudRestoreAS-win y tarea apuntando a ...\CloudRestoreAS. Verificado en Windows: reapunta la tarea, el proceso queda corriendo desde -win y el sello en la version nueva. - Nuevo scripts/probar-funciones-install.ps1: extrae las funciones del instalador por AST y las ejercita contra una tarea simulada, sin elevacion. Cubre los casos limite de la comparacion de rutas (el par de prefijo en ambos sentidos, comillas, barra final, mayusculas, `..`, ruta vacia) y que Sync-AgentTaskPath falle cuando no puede corregir. BUILD.md documenta por que se compara por igualdad exacta y no por prefijo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
111
scripts/probar-funciones-install.ps1
Normal file
111
scripts/probar-funciones-install.ps1
Normal file
@@ -0,0 +1,111 @@
|
||||
<#
|
||||
Pruebas de las funciones de install.ps1, sin instalar nada.
|
||||
|
||||
Las funciones se extraen del script por AST y se ejercitan contra una tarea programada simulada.
|
||||
Así se prueba el COMPORTAMIENTO —no solo que el archivo parsee— sin necesitar elevación ni
|
||||
registrar una tarea 'CloudRestoreAS' de verdad en la máquina.
|
||||
|
||||
Complementa a emular-actualizacion-windows.ps1: ese cubre el flujo completo, este cubre los casos
|
||||
límite de la comparación de rutas, que es donde se esconden los fallos silenciosos.
|
||||
|
||||
Uso: .\probar-funciones-install.ps1
|
||||
#>
|
||||
param([string]$Installer = (Join-Path (Split-Path -Parent $PSScriptRoot) 'install.ps1'))
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$tokens = $null; $errores = $null
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseFile(
|
||||
(Resolve-Path $Installer).Path, [ref]$tokens, [ref]$errores)
|
||||
if ($errores -and $errores.Count -gt 0) {
|
||||
Write-Host "install.ps1 no parsea: $($errores.Count) error(es)" -ForegroundColor Red
|
||||
$errores | ForEach-Object { Write-Host (" L" + $_.Extent.StartLineNumber + ": " + $_.Message) }
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Variables de ámbito de script que usan las funciones.
|
||||
$Prefix = 'C:\Aduanasoft\CloudRestoreAS-win'
|
||||
$dest = Join-Path $Prefix 'CloudRestoreAS.exe'
|
||||
$TaskName = 'CloudRestoreAS'
|
||||
$ProcName = 'CloudRestoreAS'
|
||||
|
||||
$queremos = @('Write-Step', 'Write-Ok', 'Write-Warn', 'Get-NormalizedPath', 'Test-SamePath',
|
||||
'Get-AgentTaskExecute', 'Repair-AgentTaskPath', 'Sync-AgentTaskPath')
|
||||
foreach ($f in $ast.FindAll({ param($n)
|
||||
$n -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true)) {
|
||||
if ($queremos -contains $f.Name) { . ([scriptblock]::Create($f.Extent.Text)) }
|
||||
}
|
||||
|
||||
$fallos = 0
|
||||
function Assert($cond, $msg) {
|
||||
if ($cond) { Write-Host " OK $msg" } else { Write-Host " FALLA $msg" -ForegroundColor Red; $script:fallos++ }
|
||||
}
|
||||
|
||||
Write-Host '=== Test-SamePath: rutas donde una es prefijo de cadena de la otra ==='
|
||||
# El caso que existe en produccion. Un `-like "$a*"` o un StartsWith aqui daria por iguales dos
|
||||
# instalaciones distintas, no se corregiria la tarea, y la actualizacion no surtiria efecto.
|
||||
$porOmision = 'C:\Aduanasoft\CloudRestoreAS'
|
||||
$personalizada = 'C:\Aduanasoft\CloudRestoreAS-win'
|
||||
Assert (-not (Test-SamePath $porOmision $personalizada)) 'no confunde la ruta por omision con la -win'
|
||||
Assert (-not (Test-SamePath $personalizada $porOmision)) 'ni al reves'
|
||||
Assert (-not (Test-SamePath "$porOmision\CloudRestoreAS.exe" "$personalizada\CloudRestoreAS.exe")) `
|
||||
'tampoco con el ejecutable completo'
|
||||
Assert (Test-SamePath $personalizada $personalizada) 'y la personalizada sigue siendo igual a si misma'
|
||||
|
||||
Write-Host '=== Test-SamePath: normalizacion ==='
|
||||
Assert (Test-SamePath "`"$personalizada`"" $personalizada) 'tolera comillas (la tarea las guarda asi)'
|
||||
Assert (Test-SamePath $personalizada.ToUpper() $personalizada) 'NTFS no distingue mayusculas'
|
||||
Assert (Test-SamePath "$personalizada\" $personalizada) 'ignora la barra final'
|
||||
Assert (Test-SamePath "$Prefix\..\CloudRestoreAS-win\x.exe" "$Prefix\x.exe") 'normaliza .. en la ruta'
|
||||
Assert (-not (Test-SamePath '' $personalizada)) 'una ruta vacia no es igual a nada'
|
||||
|
||||
Write-Host '=== Get-AgentTaskExecute ==='
|
||||
function Get-AgentTask { [pscustomobject]@{ Actions = @(
|
||||
[pscustomobject]@{ Execute = "`"$porOmision\CloudRestoreAS.exe`""; Arguments = '--start-engine --headless' }) } }
|
||||
Assert ((Get-AgentTaskExecute) -eq "$porOmision\CloudRestoreAS.exe") 'devuelve la ruta sin comillas'
|
||||
|
||||
# Una accion ComHandler no tiene .Execute: con StrictMode, tocarla a ciegas seria un error.
|
||||
function Get-AgentTask { [pscustomobject]@{ Actions = @(
|
||||
[pscustomobject]@{ ClassId = '{guid}' },
|
||||
[pscustomobject]@{ Execute = "$porOmision\CloudRestoreAS.exe"; Arguments = '' }) } }
|
||||
Assert ((Get-AgentTaskExecute) -eq "$porOmision\CloudRestoreAS.exe") 'se salta acciones sin Execute'
|
||||
|
||||
function Get-AgentTask { $null }
|
||||
Assert ((Get-AgentTaskExecute) -eq '') 'sin tarea devuelve cadena vacia'
|
||||
|
||||
Write-Host '=== Sync-AgentTaskPath: el fallo silencioso ==='
|
||||
$script:reapuntadoA = $null
|
||||
$script:argsPreservados = $null
|
||||
function Set-ScheduledTask { param($TaskName, $Action)
|
||||
$ejec = @($Action | Where-Object { $_.PSObject.Properties['Execute'] -and $_.Execute })
|
||||
$script:reapuntadoA = $ejec[0].Execute
|
||||
$script:argsPreservados = $ejec[0].Arguments
|
||||
return $true }
|
||||
function New-ScheduledTaskAction { param($Execute, $Argument, $WorkingDirectory)
|
||||
[pscustomobject]@{ Execute = $Execute; Arguments = $Argument } }
|
||||
|
||||
function Get-AgentTask { [pscustomobject]@{ Actions = @(
|
||||
[pscustomobject]@{ Execute = "$porOmision\CloudRestoreAS.exe"; Arguments = '--start-engine --headless' }) } }
|
||||
Sync-AgentTaskPath
|
||||
Assert ($script:reapuntadoA -eq $dest) "reapunta de la carpeta por omision a $dest"
|
||||
Assert ($script:argsPreservados -eq '--start-engine --headless') 'conserva los argumentos originales'
|
||||
|
||||
$script:reapuntadoA = $null
|
||||
function Get-AgentTask { [pscustomobject]@{ Actions = @(
|
||||
[pscustomobject]@{ Execute = $dest; Arguments = '--start-engine --headless' }) } }
|
||||
Sync-AgentTaskPath
|
||||
Assert ($null -eq $script:reapuntadoA) 'una tarea ya alineada no se toca'
|
||||
|
||||
# Si no se puede corregir tiene que FALLAR, no arrancar el binario viejo en silencio.
|
||||
function Set-ScheduledTask { param($TaskName, $Action) throw 'Acceso denegado' }
|
||||
function Get-AgentTask { [pscustomobject]@{ Actions = @(
|
||||
[pscustomobject]@{ Execute = "$porOmision\CloudRestoreAS.exe"; Arguments = '' }) } }
|
||||
$lanzo = $false; $msg = ''
|
||||
try { Sync-AgentTaskPath } catch { $lanzo = $true; $msg = $_.Exception.Message }
|
||||
Assert $lanzo 'sin permiso para corregir -> lanza en vez de seguir'
|
||||
Assert ($lanzo -and $msg -match 'sin efecto') 'el mensaje explica que la actualizacion no surtiria efecto'
|
||||
|
||||
Write-Host ''
|
||||
if ($fallos -gt 0) { Write-Host "FALLOS: $fallos" -ForegroundColor Red; exit 1 }
|
||||
Write-Host 'TODO OK' -ForegroundColor Green
|
||||
Reference in New Issue
Block a user