mirror of
https://github.com/coder/coder.git
synced 2025-07-06 15:41:45 +00:00
chore: refactor time.Duration -> int64 milliseconds for FE consumption (#1944)
* Changes all public-facing codersdk types to use a plain int64 (milliseconds) instead of time.Duration. * Makes autostart_schedule a *string as it may not be present. * Adds a utils/ptr package with some useful methods.
This commit is contained in:
@ -14,6 +14,7 @@ import (
|
||||
"github.com/coder/coder/coderd/autobuild/schedule"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/util/ptr"
|
||||
"github.com/coder/coder/codersdk"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@ -44,7 +45,7 @@ func TestExecutorAutostartOK(t *testing.T) {
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
|
||||
Schedule: sched.String(),
|
||||
Schedule: ptr.Ref(sched.String()),
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
@ -95,7 +96,7 @@ func TestExecutorAutostartTemplateUpdated(t *testing.T) {
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
|
||||
Schedule: sched.String(),
|
||||
Schedule: ptr.Ref(sched.String()),
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
@ -138,7 +139,7 @@ func TestExecutorAutostartAlreadyRunning(t *testing.T) {
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
|
||||
Schedule: sched.String(),
|
||||
Schedule: ptr.Ref(sched.String()),
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
@ -316,12 +317,12 @@ func TestExecutorAutostopNotEnabled(t *testing.T) {
|
||||
})
|
||||
// Given: we have a user with a workspace that has no TTL set
|
||||
workspace = mustProvisionWorkspace(t, client, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.TTL = nil
|
||||
cwr.TTLMillis = nil
|
||||
})
|
||||
)
|
||||
|
||||
// Given: workspace has no TTL set
|
||||
require.Nil(t, workspace.TTL)
|
||||
require.Nil(t, workspace.TTLMillis)
|
||||
|
||||
// Given: workspace is running
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition)
|
||||
@ -359,7 +360,7 @@ func TestExecutorWorkspaceDeleted(t *testing.T) {
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
|
||||
Schedule: sched.String(),
|
||||
Schedule: ptr.Ref(sched.String()),
|
||||
}))
|
||||
|
||||
// Given: workspace is deleted
|
||||
@ -402,7 +403,7 @@ func TestExecutorWorkspaceAutostartTooEarly(t *testing.T) {
|
||||
sched, err := schedule.Weekly(futureTimeCron)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
|
||||
Schedule: sched.String(),
|
||||
Schedule: ptr.Ref(sched.String()),
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
@ -461,7 +462,7 @@ func TestExecutorWorkspaceAutostopNoWaitChangedMyMind(t *testing.T) {
|
||||
)
|
||||
|
||||
// Given: the user changes their mind and decides their workspace should not auto-stop
|
||||
err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{TTL: nil})
|
||||
err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{TTLMillis: nil})
|
||||
require.NoError(t, err)
|
||||
|
||||
// When: the autobuild executor ticks after the deadline
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
"github.com/coder/coder/coderd/util/ptr"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"github.com/fullsailor/pkcs7"
|
||||
@ -399,8 +400,8 @@ func CreateWorkspace(t *testing.T, client *codersdk.Client, organization uuid.UU
|
||||
req := codersdk.CreateWorkspaceRequest{
|
||||
TemplateID: templateID,
|
||||
Name: randomUsername(),
|
||||
AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"),
|
||||
TTL: ptr(8 * time.Hour),
|
||||
AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"),
|
||||
TTLMillis: ptr.Ref((8 * time.Hour).Milliseconds()),
|
||||
}
|
||||
for _, mutator := range mutators {
|
||||
mutator(&req)
|
||||
@ -602,7 +603,3 @@ type roundTripper func(req *http.Request) (*http.Response, error)
|
||||
func (r roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return r(req)
|
||||
}
|
||||
|
||||
func ptr[T any](x T) *T {
|
||||
return &x
|
||||
}
|
||||
|
23
coderd/util/ptr/ptr.go
Normal file
23
coderd/util/ptr/ptr.go
Normal file
@ -0,0 +1,23 @@
|
||||
// Package ptr contains some utility methods related to pointers.
|
||||
package ptr
|
||||
|
||||
import "golang.org/x/exp/constraints"
|
||||
|
||||
type number interface {
|
||||
constraints.Integer | constraints.Float
|
||||
}
|
||||
|
||||
// Ref returns a reference to v.
|
||||
func Ref[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
// NilOrEmpty returns true if s is nil or the empty string.
|
||||
func NilOrEmpty(s *string) bool {
|
||||
return s == nil || *s == ""
|
||||
}
|
||||
|
||||
// NilOrZero returns true if v is nil or 0.
|
||||
func NilOrZero[T number](v *T) bool {
|
||||
return v == nil || *v == 0
|
||||
}
|
81
coderd/util/ptr/ptr_test.go
Normal file
81
coderd/util/ptr/ptr_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
package ptr_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/coder/coder/coderd/util/ptr"
|
||||
)
|
||||
|
||||
func Test_Ref_Deref(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("String", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
val := "test"
|
||||
p := ptr.Ref(val)
|
||||
assert.Equal(t, &val, p)
|
||||
})
|
||||
|
||||
t.Run("Bool", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
val := true
|
||||
p := ptr.Ref(val)
|
||||
assert.Equal(t, &val, p)
|
||||
})
|
||||
|
||||
t.Run("Int64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
val := int64(42)
|
||||
p := ptr.Ref(val)
|
||||
assert.Equal(t, &val, p)
|
||||
})
|
||||
|
||||
t.Run("Float64", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
val := float64(3.14159)
|
||||
p := ptr.Ref(val)
|
||||
assert.Equal(t, &val, p)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NilOrEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
nilString := (*string)(nil)
|
||||
emptyString := ""
|
||||
nonEmptyString := "hi"
|
||||
|
||||
assert.True(t, ptr.NilOrEmpty(nilString))
|
||||
assert.True(t, ptr.NilOrEmpty(&emptyString))
|
||||
assert.False(t, ptr.NilOrEmpty(&nonEmptyString))
|
||||
}
|
||||
|
||||
func Test_NilOrZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
nilInt64 := (*int64)(nil)
|
||||
nilFloat64 := (*float64)(nil)
|
||||
nilDuration := (*time.Duration)(nil)
|
||||
|
||||
zeroInt64 := int64(0)
|
||||
zeroFloat64 := float64(0.0)
|
||||
zeroDuration := time.Duration(0)
|
||||
|
||||
nonZeroInt64 := int64(1)
|
||||
nonZeroFloat64 := float64(3.14159)
|
||||
nonZeroDuration := time.Hour
|
||||
|
||||
assert.True(t, ptr.NilOrZero(nilInt64))
|
||||
assert.True(t, ptr.NilOrZero(nilFloat64))
|
||||
assert.True(t, ptr.NilOrZero(nilDuration))
|
||||
|
||||
assert.True(t, ptr.NilOrZero(&zeroInt64))
|
||||
assert.True(t, ptr.NilOrZero(&zeroFloat64))
|
||||
assert.True(t, ptr.NilOrZero(&zeroDuration))
|
||||
|
||||
assert.False(t, ptr.NilOrZero(&nonZeroInt64))
|
||||
assert.False(t, ptr.NilOrZero(&nonZeroFloat64))
|
||||
assert.False(t, ptr.NilOrZero(&nonZeroDuration))
|
||||
}
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/coder/coder/coderd/httpapi"
|
||||
"github.com/coder/coder/coderd/httpmw"
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
"github.com/coder/coder/coderd/util/ptr"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
@ -345,7 +346,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
||||
dbAutostartSchedule.String = *createWorkspace.AutostartSchedule
|
||||
}
|
||||
|
||||
dbTTL, err := validWorkspaceTTL(createWorkspace.TTL)
|
||||
dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
|
||||
Message: "validate workspace ttl",
|
||||
@ -527,20 +528,15 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var dbSched sql.NullString
|
||||
if req.Schedule != "" {
|
||||
validSched, err := schedule.Weekly(req.Schedule)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
|
||||
Message: fmt.Sprintf("invalid autostart schedule: %s", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
dbSched.String = validSched.String()
|
||||
dbSched.Valid = true
|
||||
dbSched, err := validWorkspaceSchedule(req.Schedule)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
|
||||
Message: fmt.Sprintf("invalid autostart schedule: %s", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := api.Database.UpdateWorkspaceAutostart(r.Context(), database.UpdateWorkspaceAutostartParams{
|
||||
err = api.Database.UpdateWorkspaceAutostart(r.Context(), database.UpdateWorkspaceAutostartParams{
|
||||
ID: workspace.ID,
|
||||
AutostartSchedule: dbSched,
|
||||
})
|
||||
@ -564,7 +560,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
dbTTL, err := validWorkspaceTTL(req.TTL)
|
||||
dbTTL, err := validWorkspaceTTLMillis(req.TTLMillis)
|
||||
if err != nil {
|
||||
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
|
||||
Message: "validate workspace ttl",
|
||||
@ -830,13 +826,18 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data
|
||||
}
|
||||
return apiWorkspaces, nil
|
||||
}
|
||||
|
||||
func convertWorkspace(
|
||||
workspace database.Workspace,
|
||||
workspaceBuild database.WorkspaceBuild,
|
||||
job database.ProvisionerJob,
|
||||
template database.Template,
|
||||
owner database.User) codersdk.Workspace {
|
||||
var autostartSchedule *string
|
||||
if workspace.AutostartSchedule.Valid {
|
||||
autostartSchedule = &workspace.AutostartSchedule.String
|
||||
}
|
||||
|
||||
ttlMillis := convertWorkspaceTTLMillis(workspace.Ttl)
|
||||
return codersdk.Workspace{
|
||||
ID: workspace.ID,
|
||||
CreatedAt: workspace.CreatedAt,
|
||||
@ -848,25 +849,27 @@ func convertWorkspace(
|
||||
TemplateName: template.Name,
|
||||
Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(),
|
||||
Name: workspace.Name,
|
||||
AutostartSchedule: workspace.AutostartSchedule.String,
|
||||
TTL: convertSQLNullInt64(workspace.Ttl),
|
||||
AutostartSchedule: autostartSchedule,
|
||||
TTLMillis: ttlMillis,
|
||||
}
|
||||
}
|
||||
|
||||
func convertSQLNullInt64(i sql.NullInt64) *time.Duration {
|
||||
func convertWorkspaceTTLMillis(i sql.NullInt64) *int64 {
|
||||
if !i.Valid {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (*time.Duration)(&i.Int64)
|
||||
millis := time.Duration(i.Int64).Milliseconds()
|
||||
return &millis
|
||||
}
|
||||
|
||||
func validWorkspaceTTL(ttl *time.Duration) (sql.NullInt64, error) {
|
||||
if ttl == nil {
|
||||
func validWorkspaceTTLMillis(millis *int64) (sql.NullInt64, error) {
|
||||
if ptr.NilOrZero(millis) {
|
||||
return sql.NullInt64{}, nil
|
||||
}
|
||||
|
||||
truncated := ttl.Truncate(time.Minute)
|
||||
dur := time.Duration(*millis) * time.Millisecond
|
||||
truncated := dur.Truncate(time.Minute)
|
||||
if truncated < time.Minute {
|
||||
return sql.NullInt64{}, xerrors.New("ttl must be at least one minute")
|
||||
}
|
||||
@ -902,3 +905,19 @@ func validWorkspaceDeadline(old, new time.Time) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validWorkspaceSchedule(s *string) (sql.NullString, error) {
|
||||
if ptr.NilOrEmpty(s) {
|
||||
return sql.NullString{}, nil
|
||||
}
|
||||
|
||||
_, err := schedule.Weekly(*s)
|
||||
if err != nil {
|
||||
return sql.NullString{}, err
|
||||
}
|
||||
|
||||
return sql.NullString{
|
||||
Valid: true,
|
||||
String: *s,
|
||||
}, nil
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
"github.com/coder/coder/coderd/util/ptr"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -177,8 +178,8 @@ func TestPostWorkspacesByOrganization(t *testing.T) {
|
||||
req := codersdk.CreateWorkspaceRequest{
|
||||
TemplateID: template.ID,
|
||||
Name: "testing",
|
||||
AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"),
|
||||
TTL: ptr(59 * time.Second),
|
||||
AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"),
|
||||
TTLMillis: ptr.Ref((59 * time.Second).Milliseconds()),
|
||||
}
|
||||
_, err := client.CreateWorkspace(context.Background(), template.OrganizationID, req)
|
||||
require.Error(t, err)
|
||||
@ -197,8 +198,8 @@ func TestPostWorkspacesByOrganization(t *testing.T) {
|
||||
req := codersdk.CreateWorkspaceRequest{
|
||||
TemplateID: template.ID,
|
||||
Name: "testing",
|
||||
AutostartSchedule: ptr("CRON_TZ=US/Central * * * * *"),
|
||||
TTL: ptr(24*7*time.Hour + time.Minute),
|
||||
AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"),
|
||||
TTLMillis: ptr.Ref((24*7*time.Hour + time.Minute).Milliseconds()),
|
||||
}
|
||||
_, err := client.CreateWorkspace(context.Background(), template.OrganizationID, req)
|
||||
require.Error(t, err)
|
||||
@ -451,7 +452,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
schedule string
|
||||
schedule *string
|
||||
expectedError string
|
||||
at time.Time
|
||||
expectedNext time.Time
|
||||
@ -459,12 +460,12 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "disable autostart",
|
||||
schedule: "",
|
||||
schedule: ptr.Ref(""),
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "friday to monday",
|
||||
schedule: "CRON_TZ=Europe/Dublin 30 9 * * 1-5",
|
||||
schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * 1-5"),
|
||||
expectedError: "",
|
||||
at: time.Date(2022, 5, 6, 9, 31, 0, 0, dublinLoc),
|
||||
expectedNext: time.Date(2022, 5, 9, 9, 30, 0, 0, dublinLoc),
|
||||
@ -472,7 +473,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "monday to tuesday",
|
||||
schedule: "CRON_TZ=Europe/Dublin 30 9 * * 1-5",
|
||||
schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * 1-5"),
|
||||
expectedError: "",
|
||||
at: time.Date(2022, 5, 9, 9, 31, 0, 0, dublinLoc),
|
||||
expectedNext: time.Date(2022, 5, 10, 9, 30, 0, 0, dublinLoc),
|
||||
@ -481,7 +482,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
{
|
||||
// DST in Ireland began on Mar 27 in 2022 at 0100. Forward 1 hour.
|
||||
name: "DST start",
|
||||
schedule: "CRON_TZ=Europe/Dublin 30 9 * * *",
|
||||
schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * *"),
|
||||
expectedError: "",
|
||||
at: time.Date(2022, 3, 26, 9, 31, 0, 0, dublinLoc),
|
||||
expectedNext: time.Date(2022, 3, 27, 9, 30, 0, 0, dublinLoc),
|
||||
@ -490,7 +491,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
{
|
||||
// DST in Ireland ends on Oct 30 in 2022 at 0200. Back 1 hour.
|
||||
name: "DST end",
|
||||
schedule: "CRON_TZ=Europe/Dublin 30 9 * * *",
|
||||
schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 * * *"),
|
||||
expectedError: "",
|
||||
at: time.Date(2022, 10, 29, 9, 31, 0, 0, dublinLoc),
|
||||
expectedNext: time.Date(2022, 10, 30, 9, 30, 0, 0, dublinLoc),
|
||||
@ -498,17 +499,17 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "invalid location",
|
||||
schedule: "CRON_TZ=Imaginary/Place 30 9 * * 1-5",
|
||||
schedule: ptr.Ref("CRON_TZ=Imaginary/Place 30 9 * * 1-5"),
|
||||
expectedError: "status code 500: invalid autostart schedule: parse schedule: provided bad location Imaginary/Place: unknown time zone Imaginary/Place",
|
||||
},
|
||||
{
|
||||
name: "invalid schedule",
|
||||
schedule: "asdf asdf asdf ",
|
||||
schedule: ptr.Ref("asdf asdf asdf "),
|
||||
expectedError: `status code 500: invalid autostart schedule: validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ=<timezone> prefix`,
|
||||
},
|
||||
{
|
||||
name: "only 3 values",
|
||||
schedule: "CRON_TZ=Europe/Dublin 30 9 *",
|
||||
schedule: ptr.Ref("CRON_TZ=Europe/Dublin 30 9 *"),
|
||||
expectedError: `status code 500: invalid autostart schedule: validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ=<timezone> prefix`,
|
||||
},
|
||||
}
|
||||
@ -526,7 +527,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.AutostartSchedule = nil
|
||||
cwr.TTL = nil
|
||||
cwr.TTLMillis = nil
|
||||
})
|
||||
)
|
||||
|
||||
@ -547,12 +548,14 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
updated, err := client.Workspace(ctx, workspace.ID)
|
||||
require.NoError(t, err, "fetch updated workspace")
|
||||
|
||||
require.Equal(t, testCase.schedule, updated.AutostartSchedule, "expected autostart schedule to equal requested")
|
||||
|
||||
if testCase.schedule == "" {
|
||||
if testCase.schedule == nil || *testCase.schedule == "" {
|
||||
require.Nil(t, updated.AutostartSchedule)
|
||||
return
|
||||
}
|
||||
sched, err := schedule.Weekly(updated.AutostartSchedule)
|
||||
|
||||
require.EqualValues(t, *testCase.schedule, *updated.AutostartSchedule, "expected autostart schedule to equal requested")
|
||||
|
||||
sched, err := schedule.Weekly(*updated.AutostartSchedule)
|
||||
require.NoError(t, err, "parse returned schedule")
|
||||
|
||||
next := sched.Next(testCase.at)
|
||||
@ -569,7 +572,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
wsid = uuid.New()
|
||||
req = codersdk.UpdateWorkspaceAutostartRequest{
|
||||
Schedule: "9 30 1-5",
|
||||
Schedule: ptr.Ref("9 30 1-5"),
|
||||
}
|
||||
)
|
||||
|
||||
@ -586,32 +589,32 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ttl *time.Duration
|
||||
ttlMillis *int64
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "disable ttl",
|
||||
ttl: nil,
|
||||
ttlMillis: nil,
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "below minimum ttl",
|
||||
ttl: ptr(30 * time.Second),
|
||||
ttlMillis: ptr.Ref((30 * time.Second).Milliseconds()),
|
||||
expectedError: "ttl must be at least one minute",
|
||||
},
|
||||
{
|
||||
name: "minimum ttl",
|
||||
ttl: ptr(time.Minute),
|
||||
ttlMillis: ptr.Ref(time.Minute.Milliseconds()),
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "maximum ttl",
|
||||
ttl: ptr(24 * 7 * time.Hour),
|
||||
ttlMillis: ptr.Ref((24 * 7 * time.Hour).Milliseconds()),
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "above maximum ttl",
|
||||
ttl: ptr(24*7*time.Hour + time.Minute),
|
||||
ttlMillis: ptr.Ref((24*7*time.Hour + time.Minute).Milliseconds()),
|
||||
expectedError: "ttl must be less than 7 days",
|
||||
},
|
||||
}
|
||||
@ -629,15 +632,15 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
|
||||
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.AutostartSchedule = nil
|
||||
cwr.TTL = nil
|
||||
cwr.TTLMillis = nil
|
||||
})
|
||||
)
|
||||
|
||||
// ensure test invariant: new workspaces have no autostop schedule.
|
||||
require.Nil(t, workspace.TTL, "expected newly-minted workspace to have no TTL")
|
||||
require.Nil(t, workspace.TTLMillis, "expected newly-minted workspace to have no TTL")
|
||||
|
||||
err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: testCase.ttl,
|
||||
TTLMillis: testCase.ttlMillis,
|
||||
})
|
||||
|
||||
if testCase.expectedError != "" {
|
||||
@ -650,7 +653,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
|
||||
updated, err := client.Workspace(ctx, workspace.ID)
|
||||
require.NoError(t, err, "fetch updated workspace")
|
||||
|
||||
require.Equal(t, testCase.ttl, updated.TTL, "expected autostop ttl to equal requested")
|
||||
require.Equal(t, testCase.ttlMillis, updated.TTLMillis, "expected autostop ttl to equal requested")
|
||||
})
|
||||
}
|
||||
|
||||
@ -661,7 +664,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
wsid = uuid.New()
|
||||
req = codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: ptr(time.Hour),
|
||||
TTLMillis: ptr.Ref(time.Hour.Milliseconds()),
|
||||
}
|
||||
)
|
||||
|
||||
@ -685,8 +688,8 @@ func TestWorkspaceExtend(t *testing.T) {
|
||||
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
|
||||
extend = 90 * time.Minute
|
||||
_ = coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
oldDeadline = time.Now().Add(*workspace.TTL).UTC()
|
||||
newDeadline = time.Now().Add(*workspace.TTL + extend).UTC()
|
||||
oldDeadline = time.Now().Add(time.Duration(*workspace.TTLMillis) * time.Millisecond).UTC()
|
||||
newDeadline = time.Now().Add(time.Duration(*workspace.TTLMillis)*time.Millisecond + extend).UTC()
|
||||
)
|
||||
|
||||
workspace, err := client.Workspace(ctx, workspace.ID)
|
||||
@ -761,7 +764,3 @@ func mustLocation(t *testing.T, location string) *time.Location {
|
||||
|
||||
return loc
|
||||
}
|
||||
|
||||
func ptr[T any](x T) *T {
|
||||
return &x
|
||||
}
|
||||
|
Reference in New Issue
Block a user