mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: skip autostop reminder for active workspaces (#26772)
This commit is contained in:
@@ -153,9 +153,16 @@ func TestShouldRemindAutostop(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// idle places last_used_at well outside the 15-minute active threshold so the
|
||||
// active-user guard never trips. It is the default for cases that leave
|
||||
// LastUsedAt unset; cases that exercise the active-user guard set LastUsedAt
|
||||
// explicitly.
|
||||
idle := currentTick.Add(-2 * ttl)
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Build database.WorkspaceBuild
|
||||
LastUsedAt time.Time
|
||||
TemplateSchedule schedule.TemplateScheduleOptions
|
||||
Expected bool
|
||||
}{
|
||||
@@ -246,13 +253,78 @@ func TestShouldRemindAutostop(t *testing.T) {
|
||||
TemplateSchedule: schedule.TemplateScheduleOptions{TimeTilAutostopNotify: ttl},
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
// ActiveUser: the workspace was used within the 15-minute active
|
||||
// threshold and activity bumps are enabled with no max_deadline
|
||||
// ceiling, so the deadline can keep getting bumped out of the window
|
||||
// and the reminder is suppressed.
|
||||
Name: "ActiveUser",
|
||||
Build: inWindow(),
|
||||
LastUsedAt: currentTick.Add(-1 * time.Minute),
|
||||
TemplateSchedule: schedule.TemplateScheduleOptions{TimeTilAutostopNotify: ttl, ActivityBump: time.Hour},
|
||||
Expected: false,
|
||||
},
|
||||
{
|
||||
// ActiveButMaxDeadlineWithinWindow: the user is active and bumps are
|
||||
// enabled, but the hard max_deadline ceiling sits inside the lead
|
||||
// window, so a bump cannot push the stop out. The workspace will stop
|
||||
// regardless of activity, so we still remind.
|
||||
Name: "ActiveButMaxDeadlineWithinWindow",
|
||||
Build: func() database.WorkspaceBuild {
|
||||
b := inWindow()
|
||||
b.MaxDeadline = currentTick.Add(ttl / 2)
|
||||
return b
|
||||
}(),
|
||||
LastUsedAt: currentTick.Add(-1 * time.Minute),
|
||||
TemplateSchedule: schedule.TemplateScheduleOptions{TimeTilAutostopNotify: ttl, ActivityBump: time.Hour},
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
// ActiveButBumpDisabled: the user is active, but activity bumps are
|
||||
// disabled (activity_bump == 0), so the deadline cannot move. The
|
||||
// workspace will stop, so we still remind.
|
||||
Name: "ActiveButBumpDisabled",
|
||||
Build: inWindow(),
|
||||
LastUsedAt: currentTick.Add(-1 * time.Minute),
|
||||
TemplateSchedule: schedule.TemplateScheduleOptions{TimeTilAutostopNotify: ttl, ActivityBump: 0},
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
// IdleUser: the workspace was last used 20 minutes ago, outside the
|
||||
// 15-minute active threshold, so it is not active and the reminder
|
||||
// fires. Activity bumps are enabled here, so the true result is
|
||||
// genuinely due to idleness and not to disabled bumping.
|
||||
Name: "IdleUser",
|
||||
Build: inWindow(),
|
||||
LastUsedAt: currentTick.Add(-20 * time.Minute),
|
||||
TemplateSchedule: schedule.TemplateScheduleOptions{TimeTilAutostopNotify: ttl, ActivityBump: time.Hour},
|
||||
Expected: true,
|
||||
},
|
||||
{
|
||||
// Exactly at the threshold: the Go guard (< threshold) treats
|
||||
// the user as not active and reminds; the SQL complement
|
||||
// (>= threshold) keeps the row. Both agree; pins the boundary
|
||||
// against a "<"/">=" off-by-one regression.
|
||||
Name: "ActiveThresholdBoundary",
|
||||
Build: inWindow(),
|
||||
LastUsedAt: currentTick.Add(-autostopReminderActiveThreshold),
|
||||
TemplateSchedule: schedule.TemplateScheduleOptions{TimeTilAutostopNotify: ttl, ActivityBump: time.Hour},
|
||||
Expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require.Equal(t, tc.Expected, shouldRemindAutostop(tc.Build, tc.TemplateSchedule, currentTick))
|
||||
// Cases that do not exercise the active-user guard leave LastUsedAt
|
||||
// unset; default those to an idle time outside the lead window.
|
||||
lastUsedAt := tc.LastUsedAt
|
||||
if lastUsedAt.IsZero() {
|
||||
lastUsedAt = idle
|
||||
}
|
||||
|
||||
require.Equal(t, tc.Expected, shouldRemindAutostop(tc.Build, lastUsedAt, tc.TemplateSchedule, currentTick))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user