Files
PSProxmoxVE/tests/PSProxmoxVE.Tests/Integration
Clint Branham dc9b253195 fix(tests): resolve all 400 unit test failures to reach green
Cmdlet fixes:
- GetPveSnapshotCmdlet: add -Name filter; fix s.SnapName → s.Name
- GetPveStorageCmdlet: add -Storage name filter
- GetPveNetworkCmdlet: add -Iface optional filter
- NewPveNetworkCmdlet: rename Interface → Iface (consistency with Set/Remove)
- SetPveNetworkCmdlet, RemovePveNetworkCmdlet: rename Interface → Iface
- RemovePveNetworkCmdlet, RemovePveSdnZoneCmdlet, RemovePveSdnVnetCmdlet,
  RemovePveUserCmdlet: add ConfirmImpact = ConfirmImpact.High
- SetPveCloudInitConfigCmdlet: rename User → CiUser; move GetSession() first;
  remove duplicate session variable
- SendPveIsoCmdlet: add sha512 to ChecksumAlgorithm ValidateSet
- GetPveUserCmdlet: add -Enabled switch; refactor into MatchesFilters(); fix
  int? comparison (Enabled != 1)
- GetPvePermissionCmdlet: rename UgId → UserId
- SetPvePermissionCmdlet: rename RoleId → Role
- NewPveTemplateCmdlet: add ConfirmImpact.High; move GetSession() before
  ShouldProcess so -WhatIf-less calls throw session error first
- NewPveVmFromTemplateCmdlet: rename Node → TemplateNode with [Alias("Node")]
- RemovePveSnapshotCmdlet, RestorePveSnapshotCmdlet: move GetSession() before
  ShouldProcess so session check precedes confirm prompt

Test fixes:
- All 18 Pester test files: update DLL candidates to net9.0
- Fix foreach+It closure capture using -TestCases pattern
- Remove-PveVm, Remove-PveContainer no-session tests: add -Confirm:$false to
  bypass ConfirmImpact.High prompt before GetSession() check
- Get-PveStorageContent test: add mandatory -Node/-Storage params
- Send-PveIso test: create temp file to satisfy FileExistsValidation
- New-PveVmFromTemplate test: add NewVmId to parameter splat

Tooling:
- Invoke-Tests.ps1: add -FromTerraform, explicit lab params, fix TFM
  auto-detection via Select-Xml, fix Pester import, fix variable scoping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 18:27:12 -05:00
..

Integration Tests

This directory contains Pester 5 integration tests for PSProxmoxVE that exercise the module against a real, live Proxmox VE API endpoint. They are skipped by default and must be opted into explicitly.


Prerequisites

Dedicated test node — never production

Integration tests create and destroy real resources (VMs, snapshots, ISO uploads, network objects, user accounts). You must use a dedicated PVE test cluster or standalone node running Proxmox VE 8.x or 9.x. Never point these tests at a production cluster.

Recommended minimum:

  • Single-node cluster or standalone host
  • At least one storage pool with images, iso, and rootdir content types enabled
  • Network access from the machine running Pester to the PVE API port (default 8006)

Required API Token

Create a dedicated API token on the test node with the permissions listed below. Using a scoped token (rather than the root password) limits blast radius if credentials leak.

pveum user add pester@pve
pveum acl modify / --users pester@pve --roles PVEAdmin
pveum user token add pester@pve pester-ci

Minimum permissions per domain

Test area Required privilege(s)
Connection Sys.Audit
Nodes Sys.Audit
VMs (read) VM.Audit
VMs (create) VM.Allocate, VM.Config.Disk, VM.Config.Memory, VM.Config.Network
VMs (delete) VM.Allocate
VMs (power) VM.PowerMgmt
VMs (clone) VM.Clone
Storage (read) Datastore.Audit
Storage (ISO) Datastore.AllocateSpace, Datastore.AllocateTemplate
Snapshots VM.Snapshot, VM.Snapshot.Rollback
Network Sys.Modify
Users User.Modify
Templates VM.Allocate, VM.Clone
Cloud-Init VM.Config.CloudInit

Environment Variables

Set these before running the integration suite. All six are required; any missing variable causes every integration test to be skipped with a clear reason message.

Variable Description Example value
PVETEST_HOST Hostname or IP address of the test PVE node 192.168.1.10 or pve-test.internal
PVETEST_PORT PVE API port 8006
PVETEST_APITOKEN API token in USER@REALM!TOKENID=UUID format pester@pve!pester-ci=xxxxxxxx-xxxx-xxxx-xxxx-xxxx
PVETEST_NODE Node name as it appears in pvesh get /nodes pve-test1
PVETEST_STORAGE Storage pool to use for disk and ISO operations local
PVETEST_ISO_PATH Local path to a small .iso file used for upload tests /tmp/tinycorelinux.iso

Setting variables (Bash / zsh)

export PVETEST_HOST="192.168.1.10"
export PVETEST_PORT="8006"
export PVETEST_APITOKEN="pester@pve!pester-ci=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export PVETEST_NODE="pve-test1"
export PVETEST_STORAGE="local"
export PVETEST_ISO_PATH="/tmp/tinycorelinux.iso"

Setting variables (PowerShell)

$env:PVETEST_HOST      = '192.168.1.10'
$env:PVETEST_PORT      = '8006'
$env:PVETEST_APITOKEN  = 'pester@pve!pester-ci=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$env:PVETEST_NODE      = 'pve-test1'
$env:PVETEST_STORAGE   = 'local'
$env:PVETEST_ISO_PATH  = '/tmp/tinycorelinux.iso'

GitHub Actions / CI

Add the variables as repository Actions secrets and expose them as environment variables in your workflow:

env:
  PVETEST_HOST:      ${{ secrets.PVETEST_HOST }}
  PVETEST_PORT:      ${{ secrets.PVETEST_PORT }}
  PVETEST_APITOKEN:  ${{ secrets.PVETEST_APITOKEN }}
  PVETEST_NODE:      ${{ secrets.PVETEST_NODE }}
  PVETEST_STORAGE:   ${{ secrets.PVETEST_STORAGE }}
  PVETEST_ISO_PATH:  ${{ secrets.PVETEST_ISO_PATH }}

How to Run

The integration suite is tagged Integration. Use the -Tag filter so that the unit tests and integration tests can be run independently.

./Invoke-Tests.ps1 -Tier Integration

Directly with Invoke-Pester

# Run integration tests only
Invoke-Pester -Path ./tests/PSProxmoxVE.Tests -Tag Integration -Output Detailed

# Run everything (unit + integration)
Invoke-Pester -Path ./tests/PSProxmoxVE.Tests -Output Detailed

# Run unit tests only (exclude integration)
Invoke-Pester -Path ./tests/PSProxmoxVE.Tests -ExcludeTag Integration -Output Detailed

Warning — Real Resources Are Created and Destroyed

The integration tests:

  • Create VMs (named pester-test-vm, pester-clone-vm) on PVETEST_NODE
  • Delete those VMs after the test completes (via AfterAll cleanup)
  • Start and stop an existing stopped VM if one is available
  • Create and delete a snapshot on an existing stopped VM
  • Upload an ISO to PVETEST_STORAGE

The AfterAll block performs best-effort cleanup. If the test run is interrupted, leftover VMs named pester-* may remain on the test node and should be removed manually.

Always confirm you are pointing at the correct, isolated test node before running.


Planned Test Coverage

Domain Current integration tests Planned additions
Connection Connect via API token, detect server version Connect via credential (ticket auth), session expiry handling
Nodes List nodes, get node status Node resource usage metrics
VMs List, create, delete, start, stop, clone Migrate, resize disk, Get/Set-PveVmConfig, Move-PveVm
Storage List, upload ISO Get-PveStorageContent, Invoke-PveStorageDownload, Remove ISO
Snapshots Create, list, delete snapshot on stopped VM Restore snapshot, snapshots on running VM (with vmstate)
Network List node networks Create bridge, Set-PveNetwork, Invoke-PveNetworkApply
SDN (none yet — requires SDN plugin enabled on test node) Get/New/Remove zone and vnet
Users List users, verify root@pam present Create/remove user, assign role, set permission
Templates List templates (count not asserted) Convert VM to template, deploy VM from template
Cloud-Init Get cloud-init config from a stopped VM (no-throw assertion) Set cloud-init fields, verify propagation via VM config
Tasks (implicitly exercised via -Wait on lifecycle cmdlets) Get-PveTask, Wait-PveTask with custom timeout