mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-23 03:33:53 +00:00
f62f35e24d
v5 modeled memory as used | cache | free (Memory.Cache, 'reclaimable buff/cache') and the memory bar's tooltip carried a 'Shown in Proxmox' row explaining why Pulse's percentage reads lower than the Proxmox UI's cache-inclusive number — a recurring support question. The v6 rebuild deleted the field from the backend model, so the split and the reconciliation vanished product-wide. Flagged by the Proxmox overview parity audit. Backend: re-add Memory.Cache; split it out via a shared splitReclaimableMemory helper at the node resolver (node status reports truly-free directly) and the VM builder (when guest meminfo reported free pages); transport as proxmox.memoryCache on unified resources alongside swap/balloon; mock mode populates plausible cache for nodes and VMs. Frontend: cache prop on StackedMemoryBar with the v5 muted-amber segment between active and balloon, tooltip rows for reclaimable cache, truly-free Free (balloon-capped), and the 'Shown in Proxmox' reconciliation; guest and node memory adapters normalize free to truly-free at the boundary; guest and node drawers grow a Reclaimable cache row; the Proxmox nodes table passes cache and node swap through.
56 lines
1.7 KiB
Go
56 lines
1.7 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
|
)
|
|
|
|
func TestSplitReclaimableMemory(t *testing.T) {
|
|
t.Run("splits cache out of available-based free", func(t *testing.T) {
|
|
memory := models.Memory{Total: 16, Used: 6, Free: 10, Usage: 37.5}
|
|
splitReclaimableMemory(&memory, 4)
|
|
if memory.Cache != 6 {
|
|
t.Fatalf("Cache = %d, want 6", memory.Cache)
|
|
}
|
|
if memory.Free != 4 {
|
|
t.Fatalf("Free = %d, want 4", memory.Free)
|
|
}
|
|
if memory.Used != 6 || memory.Total != 16 {
|
|
t.Fatalf("Used/Total mutated: %+v", memory)
|
|
}
|
|
if got := memory.Used + memory.Cache + memory.Free; got != memory.Total {
|
|
t.Fatalf("used+cache+free = %d, want %d", got, memory.Total)
|
|
}
|
|
})
|
|
|
|
t.Run("no-op when truly free is unknown", func(t *testing.T) {
|
|
memory := models.Memory{Total: 16, Used: 6, Free: 10}
|
|
splitReclaimableMemory(&memory, 0)
|
|
if memory.Cache != 0 || memory.Free != 10 {
|
|
t.Fatalf("unexpected split: %+v", memory)
|
|
}
|
|
})
|
|
|
|
t.Run("no-op when truly free is not smaller than free", func(t *testing.T) {
|
|
memory := models.Memory{Total: 16, Used: 6, Free: 10}
|
|
splitReclaimableMemory(&memory, 10)
|
|
if memory.Cache != 0 || memory.Free != 10 {
|
|
t.Fatalf("unexpected split: %+v", memory)
|
|
}
|
|
splitReclaimableMemory(&memory, 12)
|
|
if memory.Cache != 0 || memory.Free != 10 {
|
|
t.Fatalf("unexpected split with oversized trulyFree: %+v", memory)
|
|
}
|
|
})
|
|
|
|
t.Run("no-op on nil or non-positive free", func(t *testing.T) {
|
|
splitReclaimableMemory(nil, 4)
|
|
memory := models.Memory{Total: 16, Used: 16, Free: 0}
|
|
splitReclaimableMemory(&memory, 4)
|
|
if memory.Cache != 0 {
|
|
t.Fatalf("unexpected split on zero free: %+v", memory)
|
|
}
|
|
})
|
|
}
|