import fs from 'fs' import path from 'path' describe('scripts/backup-restore.ps1', () => { const script = fs.readFileSync( path.join(process.cwd(), 'scripts/backup-restore.ps1'), 'utf8' ) it('恢复客户数据必须显式确认,不能静默覆盖', () => { expect(script).toContain('[ValidateSet("Backup", "Restore", "Verify")]') expect(script).toContain('$RestoreConfirmPhrase = "RESTORE_FLNXI_DATA"') expect(script).toContain('$ConfirmRestore -ne $RestoreConfirmPhrase') expect(script).toContain('恢复会覆盖客户数据') }) it('备份包固定保存部署文件、环境文件、状态和清单', () => { expect(script).toContain('docker-compose.prod.yml') expect(script).toContain('Copy-Item -LiteralPath $envPath') expect(script).toContain('compose-config.txt') expect(script).toContain('compose-ps.txt') expect(script).toContain('docker-images.txt') expect(script).toContain('Backup-LocalDirectory') expect(script).toContain('data.zip') expect(script).toContain('uploads.zip') expect(script).toContain('manifest.json') }) it('完整备份默认短暂停止 app,保证数据库和素材文件尽量同一时间点', () => { expect(script).toContain('[switch]$SkipStopAppForBackup') expect(script).toContain('Stop-AppForConsistentBackup') expect(script).toContain('"stop", $Service') expect(script).toContain('Restart-AppAfterConsistentBackup') expect(script).toContain('"up", "-d", $Service') expect(script).toContain('appStoppedForConsistentBackup') }) it('内置数据库走 pg_dump/psql,外部数据库不假装自动备份', () => { expect(script).toContain('Test-ExternalDatabase') expect(script).toContain('$uri = [Uri]$databaseUrl') expect(script).toContain('return ($uri.Host -ne "postgres")') expect(script).not.toContain('@[^/]*postgres[^/]*:5432') expect(script).toContain('EXTERNAL_DATABASE_BACKUP_REQUIRED.txt') expect(script).toContain('pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB"') expect(script).toContain('psql -v ON_ERROR_STOP=1') }) it('内置 MinIO 数据卷有备份和恢复路径', () => { expect(script).toContain('Backup-ObjectStorage') expect(script).toContain('Restore-ObjectStorage') expect(script).toContain('Restore-LocalDirectory') expect(script).toContain('minio-data.tar.gz') expect(script).toContain('MINIO_VOLUME_NAME') expect(script).toContain('$HelperImage = "busybox:1.36"') expect(script).toContain('Test-ExternalObjectStorage') expect(script).toContain('EXTERNAL_OBJECT_STORAGE_BACKUP_REQUIRED.txt') expect(script).toContain('externalObjectStorage') expect(script).toContain('脚本不会恢复 Compose 内置 MinIO 卷') }) it('验收动作会检查 Compose、容器状态和健康接口', () => { expect(script).toContain('"config", "--quiet"') expect(script).toContain('@("ps")') expect(script).toContain('/api/health') expect(script).toContain('$HealthTimeoutSeconds = 120') expect(script).toContain('没有通过:$healthUrl') }) })