Files
Anand d04b769670 Fix storage metrics double-counting, sign-out, SMTP plaintext, and OIDC gaps
- Fleet Overview's Storage KPI and per-connection totals (internal/api/
  overview.go) were summing shared storage once per node that mounts it,
  since PVE's own Shared flag is unreliable for storage added per-node
  without ticking it. New dedupeSharedStorage collapses those by an exact
  (name, total, used) match within a connection; local-only plugin types
  are never touched. Mirrored on the Storage page, which also now
  disambiguates same-named local pools (e.g. every node's "local-lvm") by
  node so a bar chart's category axis never gets duplicate labels.
- Sign-out: React Query keeps a query's last-successful data through a
  failed refetch, so the cached signed-in user survived the post-logout
  401 and the app never noticed. signOut() now pins ["auth","me"] to null
  directly instead of invalidating-and-hoping a refetch lands in time.
- SMTP: net/smtp.SendMail opportunistically attempts STARTTLS whenever the
  server advertises it regardless of the admin's "Use STARTTLS" toggle, so
  an internal relay with a bad cert failed sends the admin explicitly asked
  to be plaintext. A dedicated sendPlain path never attempts TLS.
- OIDC: added an "Auto-create new accounts" toggle — when off, a
  first-time SSO login for an unrecognized identity is refused instead of
  silently provisioning one. Also added RP-Initiated Logout: signing out of
  an SSO session now also ends the session at the identity provider when it
  advertises support for it (end_session_endpoint), via a stored id_token
  on OIDC sessions (new sessions.oidc_id_token column).
- ResourceAreaChart tooltips now fall back to the same yTickFormatter given
  to the axis when a series has no formatter of its own — fixes raw
  unformatted numbers in Fleet Trend and every RRD chart built on it
  (Node/Guest detail) that only ever set the axis formatter.
2026-09-03 23:17:38 +05:30

65 lines
2.9 KiB
Go

package api
import (
"testing"
"ferrum/internal/pve"
)
func TestDedupeSharedStorageCollapsesSameVolumeAcrossNodes(t *testing.T) {
// An NFS share mounted on 4 nodes without PVE's "Shared" checkbox ticked
// (Shared: 0) — cluster/resources reports it once per node, byte-for-byte
// identical each time. Must collapse to one.
rows := []pve.ClusterResource{
{Node: "pve-01", Storage: "nas", PluginType: "nfs", Shared: 0, MaxDisk: 2_000_000_000_000, Disk: 1_000_000_000_000},
{Node: "pve-02", Storage: "nas", PluginType: "nfs", Shared: 0, MaxDisk: 2_000_000_000_000, Disk: 1_000_000_000_000},
{Node: "pve-03", Storage: "nas", PluginType: "nfs", Shared: 0, MaxDisk: 2_000_000_000_000, Disk: 1_000_000_000_000},
{Node: "pve-04", Storage: "nas", PluginType: "nfs", Shared: 0, MaxDisk: 2_000_000_000_000, Disk: 1_000_000_000_000},
}
got := dedupeSharedStorage(rows)
if len(got) != 1 {
t.Fatalf("got %d rows, want 1 (deduped)", len(got))
}
if got[0].MaxDisk != 2_000_000_000_000 {
t.Errorf("MaxDisk = %d, want the single volume's real capacity, not summed across nodes", got[0].MaxDisk)
}
}
func TestDedupeSharedStorageCollapsesProperlyFlaggedShared(t *testing.T) {
rows := []pve.ClusterResource{
{Node: "pve-01", Storage: "pbs-backup", PluginType: "pbs", Shared: 1, MaxDisk: 5_000_000_000_000, Disk: 2_000_000_000_000},
{Node: "pve-02", Storage: "pbs-backup", PluginType: "pbs", Shared: 1, MaxDisk: 5_000_000_000_000, Disk: 2_000_000_000_000},
}
got := dedupeSharedStorage(rows)
if len(got) != 1 {
t.Fatalf("got %d rows, want 1 (deduped)", len(got))
}
}
func TestDedupeSharedStorageKeepsGenuinelySeparateLocalDisks(t *testing.T) {
// Same name ("local-lvm"), different nodes, different usage — this is
// real per-node capacity that must be summed, not deduped away.
rows := []pve.ClusterResource{
{Node: "pve-01", Storage: "local-lvm", PluginType: "lvmthin", Shared: 0, MaxDisk: 1_000_000_000_000, Disk: 300_000_000_000},
{Node: "pve-02", Storage: "local-lvm", PluginType: "lvmthin", Shared: 0, MaxDisk: 1_000_000_000_000, Disk: 450_000_000_000},
}
got := dedupeSharedStorage(rows)
if len(got) != 2 {
t.Fatalf("got %d rows, want 2 (local disks are never deduped)", len(got))
}
}
func TestDedupeSharedStorageKeepsDistinctVolumesEvenWithMatchingCapacity(t *testing.T) {
// Two different NFS exports that happen to be identically sized but
// currently hold different amounts of data — a real coincidence in
// total size alone isn't enough to treat them as the same volume.
rows := []pve.ClusterResource{
{Node: "pve-01", Storage: "nas-a", PluginType: "nfs", Shared: 0, MaxDisk: 1_000_000_000_000, Disk: 100_000_000_000},
{Node: "pve-01", Storage: "nas-b", PluginType: "nfs", Shared: 0, MaxDisk: 1_000_000_000_000, Disk: 200_000_000_000},
}
got := dedupeSharedStorage(rows)
if len(got) != 2 {
t.Fatalf("got %d rows, want 2 (different names, never the same volume)", len(got))
}
}