mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-07-26 07:58:14 +00:00
test(stub): add integration test stubs and documentation
All integration tests skip unless PVETEST_* environment variables are configured. README documents required API token permissions, environment variables, and planned test coverage per domain. Warning that tests create and destroy real VMs and modify network configuration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,346 @@
|
||||
#Requires -Module Pester
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Pester 5 integration tests for PSProxmoxVE.
|
||||
|
||||
These tests are tagged 'Integration' and are SKIPPED by default.
|
||||
They require a live, dedicated Proxmox VE test node and the following
|
||||
environment variables to be set:
|
||||
|
||||
PVETEST_HOST - Hostname or IP of the PVE test node
|
||||
PVETEST_PORT - API port (usually 8006)
|
||||
PVETEST_APITOKEN - API token in the format USER@REALM!TOKENID=UUID
|
||||
PVETEST_NODE - PVE node name (e.g. pve-test1)
|
||||
PVETEST_STORAGE - Storage pool name for disk/ISO operations (e.g. local)
|
||||
PVETEST_ISO_PATH - Local filesystem path to a small .iso for upload tests
|
||||
|
||||
WARNING: These tests CREATE and DESTROY real resources (VMs, snapshots,
|
||||
ISO uploads, etc.) on the target node. Never run against a production cluster.
|
||||
|
||||
To run:
|
||||
Invoke-Pester -Path ./tests/PSProxmoxVE.Tests -Tag Integration
|
||||
# or use the project's helper script:
|
||||
./Invoke-Tests.ps1 -Tier Integration
|
||||
#>
|
||||
|
||||
BeforeAll {
|
||||
# -----------------------------------------------------------------------
|
||||
# Resolve and import module
|
||||
# -----------------------------------------------------------------------
|
||||
$moduleRoot = Resolve-Path (Join-Path $PSScriptRoot '../../../src/PSProxmoxVE')
|
||||
$dllCandidates = @(
|
||||
Join-Path $moduleRoot 'bin/Debug/net8.0/PSProxmoxVE.dll'
|
||||
Join-Path $moduleRoot 'bin/Release/net8.0/PSProxmoxVE.dll'
|
||||
Join-Path $moduleRoot 'bin/Debug/net48/PSProxmoxVE.dll'
|
||||
Join-Path $moduleRoot 'bin/Release/net48/PSProxmoxVE.dll'
|
||||
)
|
||||
|
||||
$moduleDll = $dllCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||||
|
||||
if ($null -eq $moduleDll) {
|
||||
throw "PSProxmoxVE.dll not found. Build the project before running Pester tests."
|
||||
}
|
||||
|
||||
Import-Module $moduleDll -Force -ErrorAction Stop
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Check required environment variables
|
||||
# -----------------------------------------------------------------------
|
||||
$requiredVars = @(
|
||||
'PVETEST_HOST',
|
||||
'PVETEST_PORT',
|
||||
'PVETEST_APITOKEN',
|
||||
'PVETEST_NODE',
|
||||
'PVETEST_STORAGE',
|
||||
'PVETEST_ISO_PATH'
|
||||
)
|
||||
|
||||
$script:SkipReason = $null
|
||||
|
||||
foreach ($var in $requiredVars) {
|
||||
if (-not [System.Environment]::GetEnvironmentVariable($var)) {
|
||||
$script:SkipReason = (
|
||||
"No live Proxmox VE target configured. " +
|
||||
"Set environment variables: $($requiredVars -join ', ')"
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# Convenience accessors (only meaningful when SkipReason is null)
|
||||
$script:Host_ = [System.Environment]::GetEnvironmentVariable('PVETEST_HOST')
|
||||
$script:Port = [int]([System.Environment]::GetEnvironmentVariable('PVETEST_PORT') ?? '8006')
|
||||
$script:ApiToken = [System.Environment]::GetEnvironmentVariable('PVETEST_APITOKEN')
|
||||
$script:Node = [System.Environment]::GetEnvironmentVariable('PVETEST_NODE')
|
||||
$script:Storage = [System.Environment]::GetEnvironmentVariable('PVETEST_STORAGE')
|
||||
$script:IsoPath = [System.Environment]::GetEnvironmentVariable('PVETEST_ISO_PATH')
|
||||
|
||||
# Track resources created during the run so AfterAll can clean up.
|
||||
$script:CreatedVmIds = [System.Collections.Generic.List[int]]::new()
|
||||
$script:CreatedVmSnaps = [System.Collections.Generic.List[hashtable]]::new()
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
# Best-effort cleanup — remove any VMs created during the test run.
|
||||
if ($null -eq $script:SkipReason -and $script:CreatedVmIds.Count -gt 0) {
|
||||
foreach ($vmId in $script:CreatedVmIds) {
|
||||
try {
|
||||
Remove-PveVm -Node $script:Node -VmId $vmId -Force -Purge -Confirm:$false -ErrorAction SilentlyContinue
|
||||
}
|
||||
catch { <# non-fatal #> }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ===========================================================================
|
||||
# Integration Tests
|
||||
# ===========================================================================
|
||||
Describe 'Integration Tests' -Tag 'Integration' {
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Connection' {
|
||||
It 'Should connect to PVE server' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$session = Connect-PveServer `
|
||||
-Server $script:Host_ `
|
||||
-Port $script:Port `
|
||||
-ApiToken $script:ApiToken `
|
||||
-SkipCertificateCheck `
|
||||
-PassThru
|
||||
|
||||
$session | Should -Not -BeNullOrEmpty
|
||||
$session.Hostname | Should -Be $script:Host_
|
||||
$session.AuthMode.ToString() | Should -Be 'ApiToken'
|
||||
|
||||
Test-PveConnection | Should -BeTrue
|
||||
}
|
||||
|
||||
It 'Should detect server version' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$detail = Test-PveConnection -Detailed
|
||||
$detail | Should -Not -BeNullOrEmpty
|
||||
$detail.ServerVersion | Should -Not -BeNullOrEmpty
|
||||
$detail.ServerVersion.Major | Should -BeIn @(8, 9)
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Nodes' {
|
||||
It 'Should list nodes' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$nodes = Get-PveNode
|
||||
$nodes | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It 'Should get node status' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$status = Get-PveNodeStatus -Node $script:Node
|
||||
$status | Should -Not -BeNullOrEmpty
|
||||
$status.Node | Should -Be $script:Node
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'VMs' {
|
||||
It 'Should list VMs' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
# Does not assert count — the node may have zero VMs.
|
||||
{ Get-PveVm -Node $script:Node -ErrorAction Stop } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It 'Should create and remove a test VM' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$task = New-PveVm `
|
||||
-Node $script:Node `
|
||||
-Name 'pester-test-vm' `
|
||||
-Memory 512 `
|
||||
-Cores 1 `
|
||||
-Wait
|
||||
|
||||
$task | Should -Not -BeNullOrEmpty
|
||||
|
||||
# Retrieve the new VM ID from the cluster.
|
||||
$vm = Get-PveVm -Node $script:Node -Name 'pester-test-vm' |
|
||||
Select-Object -First 1
|
||||
$vm | Should -Not -BeNullOrEmpty
|
||||
|
||||
$script:CreatedVmIds.Add($vm.VmId)
|
||||
|
||||
$removeTask = Remove-PveVm `
|
||||
-Node $script:Node `
|
||||
-VmId $vm.VmId `
|
||||
-Confirm:$false `
|
||||
-Wait
|
||||
|
||||
$removeTask | Should -Not -BeNullOrEmpty
|
||||
$script:CreatedVmIds.Remove($vm.VmId) | Out-Null
|
||||
}
|
||||
|
||||
It 'Should start and stop a VM' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
# Requires at least one VM on the test node; skip if none found.
|
||||
$vm = Get-PveVm -Node $script:Node | Where-Object { $_.Status -eq 'stopped' } |
|
||||
Select-Object -First 1
|
||||
|
||||
if ($null -eq $vm) {
|
||||
Set-ItResult -Skipped -Because 'No stopped VM available on the test node'
|
||||
return
|
||||
}
|
||||
|
||||
$startTask = Start-PveVm -Node $script:Node -VmId $vm.VmId -Wait
|
||||
$startTask | Should -Not -BeNullOrEmpty
|
||||
|
||||
$stopTask = Stop-PveVm -Node $script:Node -VmId $vm.VmId -Wait
|
||||
$stopTask | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It 'Should clone a VM' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$templateVm = Get-PveVm -Node $script:Node -TemplatesOnly | Select-Object -First 1
|
||||
|
||||
if ($null -eq $templateVm) {
|
||||
Set-ItResult -Skipped -Because 'No template VM available on the test node'
|
||||
return
|
||||
}
|
||||
|
||||
$task = Copy-PveVm `
|
||||
-SourceNode $script:Node `
|
||||
-VmId $templateVm.VmId `
|
||||
-NewName 'pester-clone-vm' `
|
||||
-Full `
|
||||
-Wait
|
||||
|
||||
$task | Should -Not -BeNullOrEmpty
|
||||
|
||||
$cloned = Get-PveVm -Node $script:Node -Name 'pester-clone-vm' |
|
||||
Select-Object -First 1
|
||||
$cloned | Should -Not -BeNullOrEmpty
|
||||
|
||||
$script:CreatedVmIds.Add($cloned.VmId)
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Storage' {
|
||||
It 'Should list storage' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$storage = Get-PveStorage -Node $script:Node
|
||||
$storage | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It 'Should upload an ISO' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
if (-not (Test-Path $script:IsoPath)) {
|
||||
Set-ItResult -Skipped -Because "ISO file not found at PVETEST_ISO_PATH: $($script:IsoPath)"
|
||||
return
|
||||
}
|
||||
|
||||
{
|
||||
Send-PveIso `
|
||||
-Node $script:Node `
|
||||
-Storage $script:Storage `
|
||||
-Path $script:IsoPath `
|
||||
-ErrorAction Stop
|
||||
} | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Snapshots' {
|
||||
It 'Should create and remove a snapshot' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$vm = Get-PveVm -Node $script:Node | Where-Object { $_.Status -eq 'stopped' } |
|
||||
Select-Object -First 1
|
||||
|
||||
if ($null -eq $vm) {
|
||||
Set-ItResult -Skipped -Because 'No stopped VM available for snapshot test'
|
||||
return
|
||||
}
|
||||
|
||||
$snapName = 'pester-snap'
|
||||
|
||||
$createTask = New-PveSnapshot `
|
||||
-Node $script:Node `
|
||||
-VmId $vm.VmId `
|
||||
-Name $snapName `
|
||||
-Description 'Created by Pester integration test' `
|
||||
-Wait
|
||||
|
||||
$createTask | Should -Not -BeNullOrEmpty
|
||||
|
||||
$snapshots = Get-PveSnapshot -Node $script:Node -VmId $vm.VmId
|
||||
$snapshots | Where-Object { $_.Name -eq $snapName } | Should -Not -BeNullOrEmpty
|
||||
|
||||
$removeTask = Remove-PveSnapshot `
|
||||
-Node $script:Node `
|
||||
-VmId $vm.VmId `
|
||||
-Name $snapName `
|
||||
-Confirm:$false `
|
||||
-Wait
|
||||
|
||||
$removeTask | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Network' {
|
||||
It 'Should list networks' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$networks = Get-PveNetwork -Node $script:Node
|
||||
$networks | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Users' {
|
||||
It 'Should list users' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$users = Get-PveUser
|
||||
$users | Should -Not -BeNullOrEmpty
|
||||
# root@pam is always present
|
||||
$users | Where-Object { $_.UserId -eq 'root@pam' } | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Templates' {
|
||||
It 'Should list templates' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
# Zero templates is acceptable; just verify the cmdlet does not throw.
|
||||
{ Get-PveTemplate -Node $script:Node -ErrorAction Stop } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
Context 'Cloud-Init' {
|
||||
It 'Should get cloud-init config' {
|
||||
if ($script:SkipReason) { Set-ItResult -Skipped -Because $script:SkipReason; return }
|
||||
|
||||
$ciVm = Get-PveVm -Node $script:Node | Where-Object { $_.Status -eq 'stopped' } |
|
||||
Select-Object -First 1
|
||||
|
||||
if ($null -eq $ciVm) {
|
||||
Set-ItResult -Skipped -Because 'No stopped VM available for cloud-init test'
|
||||
return
|
||||
}
|
||||
|
||||
# Get-PveCloudInitConfig should not throw even if the VM has no cloud-init drive.
|
||||
{ Get-PveCloudInitConfig -Node $script:Node -VmId $ciVm.VmId -ErrorAction Stop } |
|
||||
Should -Not -Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
# 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)
|
||||
|
||||
```bash
|
||||
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)
|
||||
|
||||
```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:
|
||||
|
||||
```yaml
|
||||
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.
|
||||
|
||||
### Via the project helper script (recommended)
|
||||
|
||||
```powershell
|
||||
./Invoke-Tests.ps1 -Tier Integration
|
||||
```
|
||||
|
||||
### Directly with Invoke-Pester
|
||||
|
||||
```powershell
|
||||
# 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 |
|
||||
Reference in New Issue
Block a user