213 lines
7.7 KiB
Go
213 lines
7.7 KiB
Go
package tasks
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
"vctp/db"
|
|
"vctp/internal/settings"
|
|
)
|
|
|
|
func TestSnapshotTableCompatModeSettingControlsTaskBehaviorFlag(t *testing.T) {
|
|
task := &CronTask{}
|
|
if !task.snapshotTableCompatModeEnabled() {
|
|
t.Fatal("expected default snapshot_table_compat_mode=true when settings are absent")
|
|
}
|
|
|
|
task.Settings = &settings.Settings{Values: &settings.SettingsYML{}}
|
|
if !task.snapshotTableCompatModeEnabled() {
|
|
t.Fatal("expected default snapshot_table_compat_mode=true when value is unset")
|
|
}
|
|
|
|
disabled := false
|
|
task.Settings.Values.Settings.SnapshotTableCompatMode = &disabled
|
|
if task.snapshotTableCompatModeEnabled() {
|
|
t.Fatal("expected snapshot_table_compat_mode=false to disable legacy snapshot-table writes")
|
|
}
|
|
|
|
enabled := true
|
|
task.Settings.Values.Settings.SnapshotTableCompatMode = &enabled
|
|
if !task.snapshotTableCompatModeEnabled() {
|
|
t.Fatal("expected snapshot_table_compat_mode=true to enable legacy snapshot-table writes")
|
|
}
|
|
}
|
|
|
|
func TestManualDailyAggregate_SQLFallback_LegacyTablesAndReport(t *testing.T) {
|
|
ctx := context.Background()
|
|
dbConn := newTasksTestDB(t)
|
|
task := newTasksTestCronTaskForAggregateFlow(t, dbConn)
|
|
t.Setenv("DAILY_AGG_SQL", "1")
|
|
t.Setenv("DAILY_AGG_GO", "")
|
|
|
|
dayStart := time.Date(2026, time.March, 15, 0, 0, 0, 0, time.UTC)
|
|
t1 := dayStart.Add(1 * time.Hour).Unix()
|
|
t2 := dayStart.Add(2 * time.Hour).Unix()
|
|
|
|
table1, err := hourlyInventoryTableName(time.Unix(t1, 0).UTC())
|
|
if err != nil {
|
|
t.Fatalf("failed to build first hourly table name: %v", err)
|
|
}
|
|
table2, err := hourlyInventoryTableName(time.Unix(t2, 0).UTC())
|
|
if err != nil {
|
|
t.Fatalf("failed to build second hourly table name: %v", err)
|
|
}
|
|
for _, table := range []string{table1, table2} {
|
|
if err := db.EnsureSnapshotTable(ctx, dbConn, table); err != nil {
|
|
t.Fatalf("failed to ensure hourly snapshot table %s: %v", table, err)
|
|
}
|
|
}
|
|
|
|
seeds := []hourlySeedRow{
|
|
{SnapshotTime: t1, Name: "vm-a", Vcenter: "vc-a", VmID: "vm-a", VmUUID: "uuid-a", ResourcePool: "Tin", Datacenter: "dc-a", Cluster: "cluster-a", Folder: "/prod", ProvisionedDisk: 100, VcpuCount: 2, RamGB: 8, CreationTime: dayStart.Add(-24 * time.Hour).Unix(), IsTemplate: "FALSE", PoweredOn: "TRUE", SrmPlaceholder: "FALSE"},
|
|
{SnapshotTime: t2, Name: "vm-a", Vcenter: "vc-a", VmID: "vm-a", VmUUID: "uuid-a", ResourcePool: "Gold", Datacenter: "dc-a", Cluster: "cluster-a", Folder: "/prod", ProvisionedDisk: 120, VcpuCount: 4, RamGB: 8, CreationTime: dayStart.Add(-24 * time.Hour).Unix(), IsTemplate: "FALSE", PoweredOn: "TRUE", SrmPlaceholder: "FALSE"},
|
|
{SnapshotTime: t2, Name: "vm-b", Vcenter: "vc-a", VmID: "vm-b", VmUUID: "uuid-b", ResourcePool: "Bronze", Datacenter: "dc-a", Cluster: "cluster-a", Folder: "/prod", ProvisionedDisk: 40, VcpuCount: 1, RamGB: 4, CreationTime: dayStart.Add(-48 * time.Hour).Unix(), IsTemplate: "FALSE", PoweredOn: "TRUE", SrmPlaceholder: "FALSE"},
|
|
}
|
|
for _, row := range seeds {
|
|
table, tableErr := hourlyInventoryTableName(time.Unix(row.SnapshotTime, 0).UTC())
|
|
if tableErr != nil {
|
|
t.Fatalf("failed to build hourly table for seed row: %v", tableErr)
|
|
}
|
|
if err := insertHourlySnapshotSeedRow(ctx, dbConn, table, row); err != nil {
|
|
t.Fatalf("failed to insert hourly snapshot seed row: %v", err)
|
|
}
|
|
}
|
|
|
|
if err := task.aggregateDailySummaryWithMode(ctx, dayStart, true, false); err != nil {
|
|
t.Fatalf("aggregateDailySummaryWithMode (legacy SQL fallback) failed: %v", err)
|
|
}
|
|
|
|
summaryTable, err := dailySummaryTableName(dayStart)
|
|
if err != nil {
|
|
t.Fatalf("failed to build daily summary table name: %v", err)
|
|
}
|
|
rows, err := loadDailySummaryRows(ctx, dbConn, summaryTable)
|
|
if err != nil {
|
|
t.Fatalf("failed to load daily summary rows: %v", err)
|
|
}
|
|
if len(rows) != 2 {
|
|
t.Fatalf("unexpected daily summary row count: got %d want %d", len(rows), 2)
|
|
}
|
|
|
|
assertSnapshotRegistryRow(t, ctx, dbConn, "daily", summaryTable, dayStart.Unix(), int64(len(rows)))
|
|
assertSummaryCacheMatchesByVcenter(t, ctx, dbConn, summaryTable, "daily", dayStart.Unix())
|
|
|
|
reportPath := filepath.Join(task.Settings.Values.Settings.ReportsDir, summaryTable+".xlsx")
|
|
if _, err := os.Stat(reportPath); err != nil {
|
|
t.Fatalf("expected daily report file at %s: %v", reportPath, err)
|
|
}
|
|
}
|
|
|
|
func TestManualMonthlyAggregate_SQLFallback_LegacyTablesAndReport(t *testing.T) {
|
|
ctx := context.Background()
|
|
dbConn := newTasksTestDB(t)
|
|
task := newTasksTestCronTaskForAggregateFlow(t, dbConn)
|
|
t.Setenv("MONTHLY_AGG_SQL", "1")
|
|
t.Setenv("MONTHLY_AGG_GO", "")
|
|
|
|
monthStart := time.Date(2026, time.April, 1, 0, 0, 0, 0, time.UTC)
|
|
day1 := monthStart.AddDate(0, 0, 2)
|
|
day2 := monthStart.AddDate(0, 0, 3)
|
|
|
|
day1Table, err := dailySummaryTableName(day1)
|
|
if err != nil {
|
|
t.Fatalf("failed to build day1 summary table name: %v", err)
|
|
}
|
|
day2Table, err := dailySummaryTableName(day2)
|
|
if err != nil {
|
|
t.Fatalf("failed to build day2 summary table name: %v", err)
|
|
}
|
|
for _, table := range []string{day1Table, day2Table} {
|
|
if err := db.EnsureSummaryTable(ctx, dbConn, table); err != nil {
|
|
t.Fatalf("failed to ensure daily summary table %s: %v", table, err)
|
|
}
|
|
}
|
|
|
|
seeds := []dailySeedRow{
|
|
{
|
|
SnapshotTime: day1.Unix(),
|
|
Name: "vm-a",
|
|
Vcenter: "vc-a",
|
|
VmID: "vm-a",
|
|
VmUUID: "uuid-a",
|
|
ResourcePool: "Bronze",
|
|
Datacenter: "dc-a",
|
|
Cluster: "cluster-a",
|
|
Folder: "/prod",
|
|
ProvisionedDisk: 100,
|
|
VcpuCount: 2,
|
|
RamGB: 8,
|
|
CreationTime: monthStart.Add(-72 * time.Hour).Unix(),
|
|
IsTemplate: "FALSE",
|
|
PoweredOn: "TRUE",
|
|
SrmPlaceholder: "FALSE",
|
|
SamplesPresent: 2,
|
|
AvgVcpuCount: 2,
|
|
AvgRamGB: 8,
|
|
AvgProvisionedDisk: 100,
|
|
AvgIsPresent: 1.0,
|
|
PoolBronzePct: 100,
|
|
Bronze: 100,
|
|
},
|
|
{
|
|
SnapshotTime: day2.Unix(),
|
|
Name: "vm-a",
|
|
Vcenter: "vc-a",
|
|
VmID: "vm-a",
|
|
VmUUID: "uuid-a",
|
|
ResourcePool: "Tin",
|
|
Datacenter: "dc-a",
|
|
Cluster: "cluster-a",
|
|
Folder: "/prod",
|
|
ProvisionedDisk: 120,
|
|
VcpuCount: 4,
|
|
RamGB: 12,
|
|
CreationTime: monthStart.Add(-72 * time.Hour).Unix(),
|
|
IsTemplate: "FALSE",
|
|
PoweredOn: "TRUE",
|
|
SrmPlaceholder: "FALSE",
|
|
SamplesPresent: 2,
|
|
AvgVcpuCount: 4,
|
|
AvgRamGB: 12,
|
|
AvgProvisionedDisk: 120,
|
|
AvgIsPresent: 1.0,
|
|
PoolTinPct: 100,
|
|
Tin: 100,
|
|
},
|
|
}
|
|
for _, seed := range seeds {
|
|
targetTable := day1Table
|
|
if seed.SnapshotTime == day2.Unix() {
|
|
targetTable = day2Table
|
|
}
|
|
if err := insertDailySummarySeedRow(ctx, dbConn, targetTable, seed); err != nil {
|
|
t.Fatalf("failed to insert daily summary seed row: %v", err)
|
|
}
|
|
}
|
|
|
|
if err := task.aggregateMonthlySummaryWithMode(ctx, monthStart, true, false); err != nil {
|
|
t.Fatalf("aggregateMonthlySummaryWithMode (legacy SQL fallback) failed: %v", err)
|
|
}
|
|
|
|
summaryTable, err := monthlySummaryTableName(monthStart)
|
|
if err != nil {
|
|
t.Fatalf("failed to build monthly summary table name: %v", err)
|
|
}
|
|
rows, err := loadMonthlySummaryRows(ctx, dbConn, summaryTable)
|
|
if err != nil {
|
|
t.Fatalf("failed to load monthly summary rows: %v", err)
|
|
}
|
|
if len(rows) != 1 {
|
|
t.Fatalf("unexpected monthly summary row count: got %d want %d", len(rows), 1)
|
|
}
|
|
|
|
assertSnapshotRegistryRow(t, ctx, dbConn, "monthly", summaryTable, monthStart.Unix(), int64(len(rows)))
|
|
assertSummaryCacheMatchesByVcenter(t, ctx, dbConn, summaryTable, "monthly", monthStart.Unix())
|
|
|
|
reportPath := filepath.Join(task.Settings.Values.Settings.ReportsDir, summaryTable+".xlsx")
|
|
if _, err := os.Stat(reportPath); err != nil {
|
|
t.Fatalf("expected monthly report file at %s: %v", reportPath, err)
|
|
}
|
|
}
|