(t *testing.T)
| 30 | } |
| 31 | |
| 32 | func TestRuntimeAudit(t *testing.T) { |
| 33 | t.Parallel() |
| 34 | |
| 35 | // Cannot run `/copy` meta command over Exec, so comment it out. |
| 36 | runtimeAuditScript = strings.ReplaceAll(runtimeAuditScript, "\\copy", "-- \\copy") |
| 37 | |
| 38 | // Use the SELECT instead |
| 39 | runtimeAuditScript = strings.ReplaceAll(runtimeAuditScript, "-- SELECT * FROM _workspace_usage_results", "SELECT * FROM _workspace_usage_results") |
| 40 | |
| 41 | db, _, sqlDB := dbtestutil.NewDBWithSQLDB(t) |
| 42 | |
| 43 | // Setup database with some workspace runtimes |
| 44 | s := initSetup(t, db) |
| 45 | startPeriod := time.Date(2025, 12, 1, 0, 0, 0, 0, time.UTC) |
| 46 | endPeriod := time.Date(2025, 12, 31, 23, 58, 59, 0, time.UTC) |
| 47 | |
| 48 | // Shorthands (keeps vectors readable). |
| 49 | decUTC := func(d, h, m int) time.Time { return time.Date(2025, 12, d, h, m, 0, 0, time.UTC) } |
| 50 | novUTC := func(d, h, m int) time.Time { return time.Date(2025, 11, d, h, m, 0, 0, time.UTC) } |
| 51 | janUTC := func(d, h, m int) time.Time { return time.Date(2026, 1, d, h, m, 0, 0, time.UTC) } |
| 52 | |
| 53 | roundUpHours := func(end, start time.Time) int { |
| 54 | return int(math.Ceil(end.Sub(start).Hours())) |
| 55 | } |
| 56 | |
| 57 | type vec struct { |
| 58 | name string |
| 59 | builds []workspaceBuildArgs |
| 60 | expect func(createdAt time.Time, inputs []workspaceBuildArgs) int |
| 61 | } |
| 62 | |
| 63 | vectors := []vec{ |
| 64 | // ------------------------- |
| 65 | // Happy path / core logic |
| 66 | // ------------------------- |
| 67 | |
| 68 | { |
| 69 | name: "long_run_inside_window_start_to_stop_counts_and_rounds", |
| 70 | // Basic succeeded start -> stop within window. |
| 71 | builds: []workspaceBuildArgs{ |
| 72 | {at: decUTC(3, 0, 15), transition: database.WorkspaceTransitionStart, jobStatus: database.ProvisionerJobStatusSucceeded}, |
| 73 | {at: decUTC(20, 12, 0), transition: database.WorkspaceTransitionStop, jobStatus: database.ProvisionerJobStatusSucceeded}, |
| 74 | }, |
| 75 | expect: func(_ time.Time, in []workspaceBuildArgs) int { |
| 76 | return roundUpHours(in[1].at, in[0].at) |
| 77 | }, |
| 78 | }, |
| 79 | { |
| 80 | name: "failed_start_does_not_count_usage", |
| 81 | // Only succeeded starts count; failed start means no accumulation. |
| 82 | builds: []workspaceBuildArgs{ |
| 83 | {at: decUTC(5, 10, 0), transition: database.WorkspaceTransitionStart, jobStatus: database.ProvisionerJobStatusFailed}, |
| 84 | {at: decUTC(5, 11, 0), transition: database.WorkspaceTransitionStop, jobStatus: database.ProvisionerJobStatusSucceeded}, |
| 85 | }, |
| 86 | expect: func(_ time.Time, _ []workspaceBuildArgs) int { return 0 }, |
| 87 | }, |
| 88 | { |
| 89 | name: "multiple_starts_while_running_ignores_later_start_uses_first_start", |
nothing calls this directly
no test coverage detected