Files
CloudRecoveryAS/scripts/probar-funciones-install.ps1
hreyes 9255c6277e 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>
2026-07-31 11:09:47 -06:00

112 lines
5.8 KiB
PowerShell

<#
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