@@ -10,146 +10,254 @@ import (
10
10
"github.com/coder/coder/coderd/database"
11
11
"github.com/coder/coder/codersdk"
12
12
13
+ "github.com/google/uuid"
13
14
"github.com/stretchr/testify/require"
14
15
)
15
16
16
- func Test_Executor_Run (t * testing.T ) {
17
+ func Test_Executor_Autostart_OK (t * testing.T ) {
17
18
t .Parallel ()
18
19
19
- t .Run ("OK" , func (t * testing.T ) {
20
- t .Parallel ()
21
-
22
- var (
23
- ctx = context .Background ()
24
- err error
25
- tickCh = make (chan time.Time )
26
- client = coderdtest .New (t , & coderdtest.Options {
27
- LifecycleTicker : tickCh ,
28
- })
29
- // Given: we have a user with a workspace
30
- _ = coderdtest .NewProvisionerDaemon (t , client )
31
- user = coderdtest .CreateFirstUser (t , client )
32
- version = coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , nil )
33
- template = coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID )
34
- _ = coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
35
- workspace = coderdtest .CreateWorkspace (t , client , user .OrganizationID , template .ID )
36
- _ = coderdtest .AwaitWorkspaceBuildJob (t , client , workspace .LatestBuild .ID )
37
- )
38
- // Given: workspace is stopped
39
- build , err := client .CreateWorkspaceBuild (ctx , workspace .ID , codersdk.CreateWorkspaceBuildRequest {
40
- TemplateVersionID : template .ActiveVersionID ,
41
- Transition : database .WorkspaceTransitionStop ,
20
+ var (
21
+ ctx = context .Background ()
22
+ err error
23
+ tickCh = make (chan time.Time )
24
+ client = coderdtest .New (t , & coderdtest.Options {
25
+ LifecycleTicker : tickCh ,
42
26
})
43
- require .NoError (t , err , "stop workspace" )
44
- // Given: we wait for the stop to complete
45
- _ = coderdtest .AwaitWorkspaceBuildJob (t , client , build .ID )
46
-
47
- // Given: we update the workspace with its new state
48
- workspace = coderdtest .MustWorkspace (t , client , workspace .ID )
49
- // Given: we ensure the workspace is now in a stopped state
50
- require .Equal (t , database .WorkspaceTransitionStop , workspace .LatestBuild .Transition )
51
-
52
- // Given: the workspace initially has autostart disabled
53
- require .Empty (t , workspace .AutostartSchedule )
54
-
55
- // When: we enable workspace autostart
56
- sched , err := schedule .Weekly ("* * * * *" )
57
- require .NoError (t , err )
58
- require .NoError (t , client .UpdateWorkspaceAutostart (ctx , workspace .ID , codersdk.UpdateWorkspaceAutostartRequest {
59
- Schedule : sched .String (),
60
- }))
61
-
62
- // When: the lifecycle executor ticks
63
- go func () {
64
- tickCh <- time .Now ().UTC ().Add (time .Minute )
65
- }()
66
-
67
- // Then: the workspace should be started
68
- require .Eventually (t , func () bool {
69
- ws := coderdtest .MustWorkspace (t , client , workspace .ID )
70
- return ws .LatestBuild .Job .Status == codersdk .ProvisionerJobSucceeded &&
71
- ws .LatestBuild .Transition == database .WorkspaceTransitionStart
72
- }, 5 * time .Second , 250 * time .Millisecond )
73
- })
27
+ // Given: we have a user with a workspace
28
+ workspace = MustProvisionWorkspace (t , client )
29
+ )
30
+ // Given: workspace is stopped
31
+ MustTransitionWorkspace (t , client , workspace .ID , database .WorkspaceTransitionStart , database .WorkspaceTransitionStop )
74
32
75
- t .Run ("AlreadyRunning" , func (t * testing.T ) {
76
- t .Parallel ()
77
-
78
- var (
79
- ctx = context .Background ()
80
- err error
81
- tickCh = make (chan time.Time )
82
- client = coderdtest .New (t , & coderdtest.Options {
83
- LifecycleTicker : tickCh ,
84
- })
85
- // Given: we have a user with a workspace
86
- _ = coderdtest .NewProvisionerDaemon (t , client )
87
- user = coderdtest .CreateFirstUser (t , client )
88
- version = coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , nil )
89
- template = coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID )
90
- _ = coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
91
- workspace = coderdtest .CreateWorkspace (t , client , user .OrganizationID , template .ID )
92
- _ = coderdtest .AwaitWorkspaceBuildJob (t , client , workspace .LatestBuild .ID )
93
- )
94
-
95
- // Given: we ensure the workspace is now in a stopped state
96
- require .Equal (t , database .WorkspaceTransitionStart , workspace .LatestBuild .Transition )
97
-
98
- // Given: the workspace initially has autostart disabled
99
- require .Empty (t , workspace .AutostartSchedule )
100
-
101
- // When: we enable workspace autostart
102
- sched , err := schedule .Weekly ("* * * * *" )
103
- require .NoError (t , err )
104
- require .NoError (t , client .UpdateWorkspaceAutostart (ctx , workspace .ID , codersdk.UpdateWorkspaceAutostartRequest {
105
- Schedule : sched .String (),
106
- }))
107
-
108
- // When: the lifecycle executor ticks
109
- go func () {
110
- tickCh <- time .Now ().UTC ().Add (time .Minute )
111
- }()
112
-
113
- // Then: the workspace should not be started.
114
- require .Never (t , func () bool {
115
- ws := coderdtest .MustWorkspace (t , client , workspace .ID )
116
- return ws .LatestBuild .ID != workspace .LatestBuild .ID
117
- }, 5 * time .Second , 250 * time .Millisecond )
118
- })
33
+ // Given: the workspace initially has autostart disabled
34
+ require .Empty (t , workspace .AutostartSchedule )
35
+
36
+ // When: we enable workspace autostart
37
+ sched , err := schedule .Weekly ("* * * * *" )
38
+ require .NoError (t , err )
39
+ require .NoError (t , client .UpdateWorkspaceAutostart (ctx , workspace .ID , codersdk.UpdateWorkspaceAutostartRequest {
40
+ Schedule : sched .String (),
41
+ }))
42
+
43
+ // When: the lifecycle executor ticks
44
+ go func () {
45
+ tickCh <- time .Now ().UTC ().Add (time .Minute )
46
+ }()
47
+
48
+ // Then: the workspace should be started
49
+ require .Eventually (t , func () bool {
50
+ ws := coderdtest .MustWorkspace (t , client , workspace .ID )
51
+ return ws .LatestBuild .Job .Status == codersdk .ProvisionerJobSucceeded &&
52
+ ws .LatestBuild .Transition == database .WorkspaceTransitionStart
53
+ }, 5 * time .Second , 250 * time .Millisecond )
54
+ }
55
+
56
+ func Test_Executor_Autostart_AlreadyRunning (t * testing.T ) {
57
+ t .Parallel ()
58
+
59
+ var (
60
+ ctx = context .Background ()
61
+ err error
62
+ tickCh = make (chan time.Time )
63
+ client = coderdtest .New (t , & coderdtest.Options {
64
+ LifecycleTicker : tickCh ,
65
+ })
66
+ // Given: we have a user with a workspace
67
+ workspace = MustProvisionWorkspace (t , client )
68
+ )
69
+
70
+ // Given: we ensure the workspace is running
71
+ require .Equal (t , database .WorkspaceTransitionStart , workspace .LatestBuild .Transition )
72
+
73
+ // Given: the workspace initially has autostart disabled
74
+ require .Empty (t , workspace .AutostartSchedule )
75
+
76
+ // When: we enable workspace autostart
77
+ sched , err := schedule .Weekly ("* * * * *" )
78
+ require .NoError (t , err )
79
+ require .NoError (t , client .UpdateWorkspaceAutostart (ctx , workspace .ID , codersdk.UpdateWorkspaceAutostartRequest {
80
+ Schedule : sched .String (),
81
+ }))
82
+
83
+ // When: the lifecycle executor ticks
84
+ go func () {
85
+ tickCh <- time .Now ().UTC ().Add (time .Minute )
86
+ }()
87
+
88
+ // Then: the workspace should not be started.
89
+ require .Never (t , func () bool {
90
+ ws := coderdtest .MustWorkspace (t , client , workspace .ID )
91
+ return ws .LatestBuild .ID != workspace .LatestBuild .ID && ws .LatestBuild .Transition == database .WorkspaceTransitionStart
92
+ }, 5 * time .Second , 250 * time .Millisecond )
93
+ }
94
+
95
+ func Test_Executor_Autostart_NotEnabled (t * testing.T ) {
96
+ t .Parallel ()
97
+
98
+ var (
99
+ tickCh = make (chan time.Time )
100
+ client = coderdtest .New (t , & coderdtest.Options {
101
+ LifecycleTicker : tickCh ,
102
+ })
103
+ // Given: we have a user with a workspace
104
+ workspace = MustProvisionWorkspace (t , client )
105
+ )
106
+
107
+ // Given: workspace is stopped
108
+ MustTransitionWorkspace (t , client , workspace .ID , database .WorkspaceTransitionStart , database .WorkspaceTransitionStop )
109
+
110
+ // Given: the workspace has autostart disabled
111
+ require .Empty (t , workspace .AutostartSchedule )
112
+
113
+ // When: the lifecycle executor ticks
114
+ go func () {
115
+ tickCh <- time .Now ().UTC ().Add (time .Minute )
116
+ }()
117
+
118
+ // Then: the workspace should not be started.
119
+ require .Never (t , func () bool {
120
+ ws := coderdtest .MustWorkspace (t , client , workspace .ID )
121
+ return ws .LatestBuild .ID != workspace .LatestBuild .ID && ws .LatestBuild .Transition == database .WorkspaceTransitionStart
122
+ }, 5 * time .Second , 250 * time .Millisecond )
123
+ }
124
+
125
+ func Test_Executor_Autostop_OK (t * testing.T ) {
126
+ t .Parallel ()
127
+
128
+ var (
129
+ ctx = context .Background ()
130
+ err error
131
+ tickCh = make (chan time.Time )
132
+ client = coderdtest .New (t , & coderdtest.Options {
133
+ LifecycleTicker : tickCh ,
134
+ })
135
+ // Given: we have a user with a workspace
136
+ workspace = MustProvisionWorkspace (t , client )
137
+ )
138
+ // Given: workspace is running
139
+ require .Equal (t , database .WorkspaceTransitionStart , workspace .LatestBuild .Transition )
119
140
120
- t .Run ("NotEnabled" , func (t * testing.T ) {
121
- t .Parallel ()
122
-
123
- var (
124
- tickCh = make (chan time.Time )
125
- client = coderdtest .New (t , & coderdtest.Options {
126
- LifecycleTicker : tickCh ,
127
- })
128
- // Given: we have a user with a workspace
129
- _ = coderdtest .NewProvisionerDaemon (t , client )
130
- user = coderdtest .CreateFirstUser (t , client )
131
- version = coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , nil )
132
- template = coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID )
133
- _ = coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
134
- workspace = coderdtest .CreateWorkspace (t , client , user .OrganizationID , template .ID )
135
- _ = coderdtest .AwaitWorkspaceBuildJob (t , client , workspace .LatestBuild .ID )
136
- )
137
-
138
- // Given: we ensure the workspace is now in a stopped state
139
- require .Equal (t , database .WorkspaceTransitionStart , workspace .LatestBuild .Transition )
140
-
141
- // Given: the workspace has autostart disabled
142
- require .Empty (t , workspace .AutostartSchedule )
143
-
144
- // When: the lifecycle executor ticks
145
- go func () {
146
- tickCh <- time .Now ().UTC ().Add (time .Minute )
147
- }()
148
-
149
- // Then: the workspace should not be started.
150
- require .Never (t , func () bool {
151
- ws := coderdtest .MustWorkspace (t , client , workspace .ID )
152
- return ws .LatestBuild .ID != workspace .LatestBuild .ID
153
- }, 5 * time .Second , 250 * time .Millisecond )
141
+ // Given: the workspace initially has autostop disabled
142
+ require .Empty (t , workspace .AutostopSchedule )
143
+
144
+ // When: we enable workspace autostop
145
+ sched , err := schedule .Weekly ("* * * * *" )
146
+ require .NoError (t , err )
147
+ require .NoError (t , client .UpdateWorkspaceAutostop (ctx , workspace .ID , codersdk.UpdateWorkspaceAutostopRequest {
148
+ Schedule : sched .String (),
149
+ }))
150
+
151
+ // When: the lifecycle executor ticks
152
+ go func () {
153
+ tickCh <- time .Now ().UTC ().Add (time .Minute )
154
+ }()
155
+
156
+ // Then: the workspace should be started
157
+ require .Eventually (t , func () bool {
158
+ ws := coderdtest .MustWorkspace (t , client , workspace .ID )
159
+ return ws .LatestBuild .ID != workspace .LatestBuild .ID && ws .LatestBuild .Transition == database .WorkspaceTransitionStart
160
+ }, 5 * time .Second , 250 * time .Millisecond )
161
+ }
162
+ func Test_Executor_Autostop_AlreadyStopped (t * testing.T ) {
163
+ t .Parallel ()
164
+
165
+ var (
166
+ ctx = context .Background ()
167
+ err error
168
+ tickCh = make (chan time.Time )
169
+ client = coderdtest .New (t , & coderdtest.Options {
170
+ LifecycleTicker : tickCh ,
171
+ })
172
+ // Given: we have a user with a workspace
173
+ workspace = MustProvisionWorkspace (t , client )
174
+ )
175
+
176
+ // Given: workspace is stopped
177
+ MustTransitionWorkspace (t , client , workspace .ID , database .WorkspaceTransitionStart , database .WorkspaceTransitionStop )
178
+
179
+ // Given: the workspace initially has autostart disabled
180
+ require .Empty (t , workspace .AutostopSchedule )
181
+
182
+ // When: we enable workspace autostart
183
+ sched , err := schedule .Weekly ("* * * * *" )
184
+ require .NoError (t , err )
185
+ require .NoError (t , client .UpdateWorkspaceAutostop (ctx , workspace .ID , codersdk.UpdateWorkspaceAutostopRequest {
186
+ Schedule : sched .String (),
187
+ }))
188
+
189
+ // When: the lifecycle executor ticks
190
+ go func () {
191
+ tickCh <- time .Now ().UTC ().Add (time .Minute )
192
+ }()
193
+
194
+ // Then: the workspace should not be stopped.
195
+ require .Never (t , func () bool {
196
+ ws := coderdtest .MustWorkspace (t , client , workspace .ID )
197
+ return ws .LatestBuild .ID == workspace .LatestBuild .ID && ws .LatestBuild .Transition == database .WorkspaceTransitionStop
198
+ }, 5 * time .Second , 250 * time .Millisecond )
199
+ }
200
+
201
+ func Test_Executor_Autostop_NotEnabled (t * testing.T ) {
202
+ t .Parallel ()
203
+
204
+ var (
205
+ tickCh = make (chan time.Time )
206
+ client = coderdtest .New (t , & coderdtest.Options {
207
+ LifecycleTicker : tickCh ,
208
+ })
209
+ // Given: we have a user with a workspace
210
+ workspace = MustProvisionWorkspace (t , client )
211
+ )
212
+
213
+ // Given: workspace is running
214
+ require .Equal (t , database .WorkspaceTransitionStart , workspace .LatestBuild .Transition )
215
+
216
+ // Given: the workspace has autostop disabled
217
+ require .Empty (t , workspace .AutostopSchedule )
218
+
219
+ // When: the lifecycle executor ticks
220
+ go func () {
221
+ tickCh <- time .Now ().UTC ().Add (time .Minute )
222
+ }()
223
+
224
+ // Then: the workspace should not be stopped.
225
+ require .Never (t , func () bool {
226
+ ws := coderdtest .MustWorkspace (t , client , workspace .ID )
227
+ return ws .LatestBuild .ID == workspace .LatestBuild .ID && ws .LatestBuild .Transition == database .WorkspaceTransitionStop
228
+ }, 5 * time .Second , 250 * time .Millisecond )
229
+ }
230
+
231
+ func MustProvisionWorkspace (t * testing.T , client * codersdk.Client ) codersdk.Workspace {
232
+ t .Helper ()
233
+ coderdtest .NewProvisionerDaemon (t , client )
234
+ user := coderdtest .CreateFirstUser (t , client )
235
+ version := coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , nil )
236
+ template := coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID )
237
+ coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
238
+ ws := coderdtest .CreateWorkspace (t , client , user .OrganizationID , template .ID )
239
+ coderdtest .AwaitWorkspaceBuildJob (t , client , ws .LatestBuild .ID )
240
+ return coderdtest .MustWorkspace (t , client , ws .ID )
241
+ }
242
+
243
+ func MustTransitionWorkspace (t * testing.T , client * codersdk.Client , workspaceID uuid.UUID , from , to database.WorkspaceTransition ) {
244
+ t .Helper ()
245
+ ctx := context .Background ()
246
+ workspace , err := client .Workspace (ctx , workspaceID )
247
+ require .NoError (t , err , "unexpected error fetching workspace" )
248
+ require .Equal (t , workspace .LatestBuild .Transition , from , "expected workspace state: %s got: %s" , from , workspace .LatestBuild .Transition )
249
+
250
+ template , err := client .Template (ctx , workspace .TemplateID )
251
+ require .NoError (t , err , "fetch workspace template" )
252
+
253
+ build , err := client .CreateWorkspaceBuild (ctx , workspace .ID , codersdk.CreateWorkspaceBuildRequest {
254
+ TemplateVersionID : template .ActiveVersionID ,
255
+ Transition : to ,
154
256
})
257
+ require .NoError (t , err , "unexpected error transitioning workspace to %s" , to )
258
+
259
+ _ = coderdtest .AwaitWorkspaceBuildJob (t , client , build .ID )
260
+
261
+ updated := coderdtest .MustWorkspace (t , client , workspace .ID )
262
+ require .Equal (t , to , updated .LatestBuild .Transition , "expected workspace to be in state %s but got %s" , to , updated .LatestBuild .Transition )
155
263
}
0 commit comments