mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
This PR adds a package lifecycle and an Executor implementation that attempts to schedule a build of workspaces with autostart configured. - lifecycle.Executor takes a chan time.Time in its constructor (e.g. time.Tick(time.Minute)) - Whenever a value is received from this channel, it executes one iteration of looping through the workspaces and triggering lifecycle operations. - When the context passed to the executor is Done, it exits. - Only workspaces that meet the following criteria will have a lifecycle operation applied to them: - Workspace has a valid and non-empty autostart or autostop schedule (either) - Workspace's last build was successful - The following transitions will be applied depending on the current workspace state: - If the workspace is currently running, it will be stopped. - If the workspace is currently stopped, it will be started. - Otherwise, nothing will be done. - Workspace builds will be created with the same parameters and template version as the last successful build (for example, template version)
96 lines
3.0 KiB
Go
96 lines
3.0 KiB
Go
package schedule_test
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/coderd/autobuild/schedule"
|
|
)
|
|
|
|
func Test_Weekly(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []struct {
|
|
name string
|
|
spec string
|
|
at time.Time
|
|
expectedNext time.Time
|
|
expectedError string
|
|
}{
|
|
{
|
|
name: "with timezone",
|
|
spec: "CRON_TZ=US/Central 30 9 * * 1-5",
|
|
at: time.Date(2022, 4, 1, 14, 29, 0, 0, time.UTC),
|
|
expectedNext: time.Date(2022, 4, 1, 14, 30, 0, 0, time.UTC),
|
|
expectedError: "",
|
|
},
|
|
{
|
|
name: "without timezone",
|
|
spec: "30 9 * * 1-5",
|
|
at: time.Date(2022, 4, 1, 9, 29, 0, 0, time.Local),
|
|
expectedNext: time.Date(2022, 4, 1, 9, 30, 0, 0, time.Local),
|
|
expectedError: "",
|
|
},
|
|
{
|
|
name: "invalid schedule",
|
|
spec: "asdfasdfasdfsd",
|
|
at: time.Time{},
|
|
expectedNext: time.Time{},
|
|
expectedError: "validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ=<timezone> prefix",
|
|
},
|
|
{
|
|
name: "invalid location",
|
|
spec: "CRON_TZ=Fictional/Country 30 9 * * 1-5",
|
|
at: time.Time{},
|
|
expectedNext: time.Time{},
|
|
expectedError: "parse schedule: provided bad location Fictional/Country: unknown time zone Fictional/Country",
|
|
},
|
|
{
|
|
name: "invalid schedule with 3 fields",
|
|
spec: "CRON_TZ=Fictional/Country 30 9 1-5",
|
|
at: time.Time{},
|
|
expectedNext: time.Time{},
|
|
expectedError: "validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ=<timezone> prefix",
|
|
},
|
|
{
|
|
name: "invalid schedule with 3 fields and no timezone",
|
|
spec: "30 9 1-5",
|
|
at: time.Time{},
|
|
expectedNext: time.Time{},
|
|
expectedError: "validate weekly schedule: expected schedule to consist of 5 fields with an optional CRON_TZ=<timezone> prefix",
|
|
},
|
|
{
|
|
name: "valid schedule with 5 fields but month and dom not set to *",
|
|
spec: "30 9 1 1 1-5",
|
|
at: time.Time{},
|
|
expectedNext: time.Time{},
|
|
expectedError: "validate weekly schedule: expected month and dom to be *",
|
|
},
|
|
{
|
|
name: "valid schedule with 5 fields and timezone but month and dom not set to *",
|
|
spec: "CRON_TZ=Europe/Dublin 30 9 1 1 1-5",
|
|
at: time.Time{},
|
|
expectedNext: time.Time{},
|
|
expectedError: "validate weekly schedule: expected month and dom to be *",
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
testCase := testCase
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
actual, err := schedule.Weekly(testCase.spec)
|
|
if testCase.expectedError == "" {
|
|
nextTime := actual.Next(testCase.at)
|
|
require.NoError(t, err)
|
|
require.Equal(t, testCase.expectedNext, nextTime)
|
|
require.Equal(t, testCase.spec, actual.String())
|
|
} else {
|
|
require.EqualError(t, err, testCase.expectedError)
|
|
require.Nil(t, actual)
|
|
}
|
|
})
|
|
}
|
|
}
|