Files
vctp2/internal/tasks/inventorySnapshots_test.go
Nathan Coad 6fbd6bc9d2
All checks were successful
continuous-integration/drone/push Build is passing
Enhance snapshot handling by backfilling provisioned disk data and updating backfill logic
2026-02-13 16:17:56 +11:00

123 lines
3.8 KiB
Go

package tasks
import (
"context"
"database/sql"
"testing"
"vctp/db"
"github.com/jmoiron/sqlx"
_ "modernc.org/sqlite"
)
func newTasksTestDB(t *testing.T) *sqlx.DB {
t.Helper()
dbConn, err := sqlx.Open("sqlite", ":memory:")
if err != nil {
t.Fatalf("failed to open sqlite test db: %v", err)
}
t.Cleanup(func() {
_ = dbConn.Close()
})
return dbConn
}
func TestBackfillSnapshotRowFromHourlyCache(t *testing.T) {
ctx := context.Background()
dbConn := newTasksTestDB(t)
if err := db.EnsureVmHourlyStats(ctx, dbConn); err != nil {
t.Fatalf("failed to ensure vm_hourly_stats: %v", err)
}
insertSQL := `
INSERT INTO vm_hourly_stats (
"SnapshotTime","Vcenter","VmId","VmUuid","Name","CreationTime","DeletionTime","ResourcePool",
"Datacenter","Cluster","Folder","ProvisionedDisk","VcpuCount","RamGB","IsTemplate","PoweredOn","SrmPlaceholder"
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
`
if _, err := dbConn.ExecContext(ctx, insertSQL,
int64(1000), "vc-a", "vm-1", "uuid-1", "demo-vm", int64(900), int64(0), "Tin",
"dc-1", "cluster-1", "/Prod", 123.4, int64(4), int64(16), "FALSE", "TRUE", "FALSE",
); err != nil {
t.Fatalf("failed to insert cache row: %v", err)
}
row := InventorySnapshotRow{
Vcenter: "vc-a",
VmId: sql.NullString{String: "vm-1", Valid: true},
Name: "demo-vm",
SnapshotTime: 2000,
ResourcePool: sql.NullString{String: "Tin", Valid: true},
SrmPlaceholder: "",
}
if !needsSnapshotBackfill(row) {
t.Fatal("expected sparse row to require backfill")
}
changed := backfillSnapshotRowFromHourlyCache(ctx, dbConn, &row)
if !changed {
t.Fatal("expected cache backfill to update the row")
}
if !row.CreationTime.Valid || row.CreationTime.Int64 != 900 {
t.Fatalf("unexpected CreationTime after backfill: %#v", row.CreationTime)
}
if !row.Cluster.Valid || row.Cluster.String != "cluster-1" {
t.Fatalf("unexpected Cluster after backfill: %#v", row.Cluster)
}
if !row.Datacenter.Valid || row.Datacenter.String != "dc-1" {
t.Fatalf("unexpected Datacenter after backfill: %#v", row.Datacenter)
}
if !row.ProvisionedDisk.Valid || row.ProvisionedDisk.Float64 != 123.4 {
t.Fatalf("unexpected ProvisionedDisk after backfill: %#v", row.ProvisionedDisk)
}
if !row.VcpuCount.Valid || row.VcpuCount.Int64 != 4 {
t.Fatalf("unexpected VcpuCount after backfill: %#v", row.VcpuCount)
}
if !row.RamGB.Valid || row.RamGB.Int64 != 16 {
t.Fatalf("unexpected RamGB after backfill: %#v", row.RamGB)
}
if row.SrmPlaceholder != "FALSE" {
t.Fatalf("unexpected SrmPlaceholder after backfill: %q", row.SrmPlaceholder)
}
if !row.VmUuid.Valid || row.VmUuid.String != "uuid-1" {
t.Fatalf("unexpected VmUuid after backfill: %#v", row.VmUuid)
}
}
func TestBackfillSnapshotRowFromHourlyCacheNoMatch(t *testing.T) {
ctx := context.Background()
dbConn := newTasksTestDB(t)
if err := db.EnsureVmHourlyStats(ctx, dbConn); err != nil {
t.Fatalf("failed to ensure vm_hourly_stats: %v", err)
}
row := InventorySnapshotRow{
Vcenter: "vc-a",
VmId: sql.NullString{String: "vm-missing", Valid: true},
}
changed := backfillSnapshotRowFromHourlyCache(ctx, dbConn, &row)
if changed {
t.Fatal("expected no backfill change for missing VM")
}
}
func TestNeedsSnapshotBackfillIgnoresDiskOnlyGap(t *testing.T) {
row := InventorySnapshotRow{
CreationTime: sql.NullInt64{Int64: 100, Valid: true},
VcpuCount: sql.NullInt64{Int64: 2, Valid: true},
RamGB: sql.NullInt64{Int64: 8, Valid: true},
Cluster: sql.NullString{String: "cluster-a", Valid: true},
Datacenter: sql.NullString{String: "dc-a", Valid: true},
SrmPlaceholder: "FALSE",
VmUuid: sql.NullString{String: "uuid-1", Valid: true},
// ProvisionedDisk intentionally missing.
}
if needsSnapshotBackfill(row) {
t.Fatal("expected disk-only gap to be non-critical for sparse-row detection")
}
}