@@ -17,6 +17,7 @@ import (
17
17
"github.com/coder/coder/v2/coderd/database"
18
18
"github.com/coder/coder/v2/coderd/database/dbfake"
19
19
"github.com/coder/coder/v2/coderd/schedule/cron"
20
+ "github.com/coder/coder/v2/coderd/util/tz"
20
21
"github.com/coder/coder/v2/codersdk"
21
22
"github.com/coder/coder/v2/pty/ptytest"
22
23
"github.com/coder/coder/v2/testutil"
@@ -30,6 +31,8 @@ import (
30
31
// It returns the owner and member clients, the database, and the workspaces.
31
32
// The workspaces are returned in the same order as they are created.
32
33
func setupTestSchedule (t * testing.T , sched * cron.Schedule ) (ownerClient , memberClient * codersdk.Client , db database.Store , ws []codersdk.Workspace ) {
34
+ t .Helper ()
35
+
33
36
ownerClient , db = coderdtest .NewWithDatabase (t , nil )
34
37
owner := coderdtest .CreateFirstUser (t , ownerClient )
35
38
memberClient , memberUser := coderdtest .CreateAnotherUserMutators (t , ownerClient , owner .OrganizationID , nil , func (r * codersdk.CreateUserRequest ) {
@@ -75,18 +78,20 @@ func setupTestSchedule(t *testing.T, sched *cron.Schedule) (ownerClient, memberC
75
78
return ownerClient , memberClient , db , ws
76
79
}
77
80
81
+ //nolint:paralleltest // t.Setenv
78
82
func TestScheduleShow (t * testing.T ) {
79
- t .Parallel ()
80
-
81
83
// Given
84
+ // Set timezone to Asia/Kolkata to surface any timezone-related bugs.
85
+ t .Setenv ("TZ" , "Asia/Kolkata" )
86
+ loc , err := tz .TimezoneIANA ()
87
+ require .NoError (t , err )
88
+ require .Equal (t , "Asia/Kolkata" , loc .String ())
82
89
sched , err := cron .Weekly ("CRON_TZ=Europe/Dublin 30 7 * * Mon-Fri" )
83
90
require .NoError (t , err , "invalid schedule" )
84
91
ownerClient , memberClient , _ , ws := setupTestSchedule (t , sched )
85
92
now := time .Now ()
86
93
87
94
t .Run ("OwnerNoArgs" , func (t * testing.T ) {
88
- t .Parallel ()
89
-
90
95
// When: owner specifies no args
91
96
inv , root := clitest .New (t , "schedule" , "show" )
92
97
//nolint:gocritic // Testing that owner user sees all
@@ -98,18 +103,16 @@ func TestScheduleShow(t *testing.T) {
98
103
// 1st workspace: a-owner-ws1 has both autostart and autostop enabled.
99
104
pty .ExpectMatch (ws [0 ].OwnerName + "/" + ws [0 ].Name )
100
105
pty .ExpectMatch (sched .Humanize ())
101
- pty .ExpectMatch (sched .Next (now ).Format (time .RFC3339 ))
106
+ pty .ExpectMatch (sched .Next (now ).In ( loc ). Format (time .RFC3339 ))
102
107
pty .ExpectMatch ("8h" )
103
- pty .ExpectMatch (ws [0 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ))
108
+ pty .ExpectMatch (ws [0 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ))
104
109
// 2nd workspace: b-owner-ws2 has only autostart enabled.
105
110
pty .ExpectMatch (ws [1 ].OwnerName + "/" + ws [1 ].Name )
106
111
pty .ExpectMatch (sched .Humanize ())
107
- pty .ExpectMatch (sched .Next (now ).Format (time .RFC3339 ))
112
+ pty .ExpectMatch (sched .Next (now ).In ( loc ). Format (time .RFC3339 ))
108
113
})
109
114
110
115
t .Run ("OwnerAll" , func (t * testing.T ) {
111
- t .Parallel ()
112
-
113
116
// When: owner lists all workspaces
114
117
inv , root := clitest .New (t , "schedule" , "show" , "--all" )
115
118
//nolint:gocritic // Testing that owner user sees all
@@ -121,24 +124,22 @@ func TestScheduleShow(t *testing.T) {
121
124
// 1st workspace: a-owner-ws1 has both autostart and autostop enabled.
122
125
pty .ExpectMatch (ws [0 ].OwnerName + "/" + ws [0 ].Name )
123
126
pty .ExpectMatch (sched .Humanize ())
124
- pty .ExpectMatch (sched .Next (now ).Format (time .RFC3339 ))
127
+ pty .ExpectMatch (sched .Next (now ).In ( loc ). Format (time .RFC3339 ))
125
128
pty .ExpectMatch ("8h" )
126
- pty .ExpectMatch (ws [0 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ))
129
+ pty .ExpectMatch (ws [0 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ))
127
130
// 2nd workspace: b-owner-ws2 has only autostart enabled.
128
131
pty .ExpectMatch (ws [1 ].OwnerName + "/" + ws [1 ].Name )
129
132
pty .ExpectMatch (sched .Humanize ())
130
- pty .ExpectMatch (sched .Next (now ).Format (time .RFC3339 ))
133
+ pty .ExpectMatch (sched .Next (now ).In ( loc ). Format (time .RFC3339 ))
131
134
// 3rd workspace: c-member-ws3 has only autostop enabled.
132
135
pty .ExpectMatch (ws [2 ].OwnerName + "/" + ws [2 ].Name )
133
136
pty .ExpectMatch ("8h" )
134
- pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ))
137
+ pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ))
135
138
// 4th workspace: d-member-ws4 has neither autostart nor autostop enabled.
136
139
pty .ExpectMatch (ws [3 ].OwnerName + "/" + ws [3 ].Name )
137
140
})
138
141
139
142
t .Run ("OwnerSearchByName" , func (t * testing.T ) {
140
- t .Parallel ()
141
-
142
143
// When: owner specifies a search query
143
144
inv , root := clitest .New (t , "schedule" , "show" , "--search" , "name:" + ws [1 ].Name )
144
145
//nolint:gocritic // Testing that owner user sees all
@@ -150,12 +151,10 @@ func TestScheduleShow(t *testing.T) {
150
151
// 2nd workspace: b-owner-ws2 has only autostart enabled.
151
152
pty .ExpectMatch (ws [1 ].OwnerName + "/" + ws [1 ].Name )
152
153
pty .ExpectMatch (sched .Humanize ())
153
- pty .ExpectMatch (sched .Next (now ).Format (time .RFC3339 ))
154
+ pty .ExpectMatch (sched .Next (now ).In ( loc ). Format (time .RFC3339 ))
154
155
})
155
156
156
157
t .Run ("OwnerOneArg" , func (t * testing.T ) {
157
- t .Parallel ()
158
-
159
158
// When: owner asks for a specific workspace by name
160
159
inv , root := clitest .New (t , "schedule" , "show" , ws [2 ].OwnerName + "/" + ws [2 ].Name )
161
160
//nolint:gocritic // Testing that owner user sees all
@@ -167,12 +166,10 @@ func TestScheduleShow(t *testing.T) {
167
166
// 3rd workspace: c-member-ws3 has only autostop enabled.
168
167
pty .ExpectMatch (ws [2 ].OwnerName + "/" + ws [2 ].Name )
169
168
pty .ExpectMatch ("8h" )
170
- pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ))
169
+ pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ))
171
170
})
172
171
173
172
t .Run ("MemberNoArgs" , func (t * testing.T ) {
174
- t .Parallel ()
175
-
176
173
// When: a member specifies no args
177
174
inv , root := clitest .New (t , "schedule" , "show" )
178
175
clitest .SetupConfig (t , memberClient , root )
@@ -183,14 +180,12 @@ func TestScheduleShow(t *testing.T) {
183
180
// 1st workspace: c-member-ws3 has only autostop enabled.
184
181
pty .ExpectMatch (ws [2 ].OwnerName + "/" + ws [2 ].Name )
185
182
pty .ExpectMatch ("8h" )
186
- pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ))
183
+ pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ))
187
184
// 2nd workspace: d-member-ws4 has neither autostart nor autostop enabled.
188
185
pty .ExpectMatch (ws [3 ].OwnerName + "/" + ws [3 ].Name )
189
186
})
190
187
191
188
t .Run ("MemberAll" , func (t * testing.T ) {
192
- t .Parallel ()
193
-
194
189
// When: a member lists all workspaces
195
190
inv , root := clitest .New (t , "schedule" , "show" , "--all" )
196
191
clitest .SetupConfig (t , memberClient , root )
@@ -206,14 +201,12 @@ func TestScheduleShow(t *testing.T) {
206
201
// 1st workspace: c-member-ws3 has only autostop enabled.
207
202
pty .ExpectMatch (ws [2 ].OwnerName + "/" + ws [2 ].Name )
208
203
pty .ExpectMatch ("8h" )
209
- pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ))
204
+ pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ))
210
205
// 2nd workspace: d-member-ws4 has neither autostart nor autostop enabled.
211
206
pty .ExpectMatch (ws [3 ].OwnerName + "/" + ws [3 ].Name )
212
207
})
213
208
214
209
t .Run ("JSON" , func (t * testing.T ) {
215
- t .Parallel ()
216
-
217
210
// When: owner lists all workspaces in JSON format
218
211
inv , root := clitest .New (t , "schedule" , "show" , "--all" , "--output" , "json" )
219
212
var buf bytes.Buffer
@@ -239,21 +232,21 @@ func TestScheduleShow(t *testing.T) {
239
232
// 1st workspace: a-owner-ws1 has both autostart and autostop enabled.
240
233
assert .Equal (t , ws [0 ].OwnerName + "/" + ws [0 ].Name , parsed [0 ]["workspace" ])
241
234
assert .Equal (t , sched .Humanize (), parsed [0 ]["starts_at" ])
242
- assert .Equal (t , sched .Next (now ).Format (time .RFC3339 ), parsed [0 ]["starts_next" ])
235
+ assert .Equal (t , sched .Next (now ).In ( loc ). Format (time .RFC3339 ), parsed [0 ]["starts_next" ])
243
236
assert .Equal (t , "8h" , parsed [0 ]["stops_after" ])
244
- assert .Equal (t , ws [0 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ), parsed [0 ]["stops_next" ])
237
+ assert .Equal (t , ws [0 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ), parsed [0 ]["stops_next" ])
245
238
// 2nd workspace: b-owner-ws2 has only autostart enabled.
246
239
assert .Equal (t , ws [1 ].OwnerName + "/" + ws [1 ].Name , parsed [1 ]["workspace" ])
247
240
assert .Equal (t , sched .Humanize (), parsed [1 ]["starts_at" ])
248
- assert .Equal (t , sched .Next (now ).Format (time .RFC3339 ), parsed [1 ]["starts_next" ])
241
+ assert .Equal (t , sched .Next (now ).In ( loc ). Format (time .RFC3339 ), parsed [1 ]["starts_next" ])
249
242
assert .Empty (t , parsed [1 ]["stops_after" ])
250
243
assert .Empty (t , parsed [1 ]["stops_next" ])
251
244
// 3rd workspace: c-member-ws3 has only autostop enabled.
252
245
assert .Equal (t , ws [2 ].OwnerName + "/" + ws [2 ].Name , parsed [2 ]["workspace" ])
253
246
assert .Empty (t , parsed [2 ]["starts_at" ])
254
247
assert .Empty (t , parsed [2 ]["starts_next" ])
255
248
assert .Equal (t , "8h" , parsed [2 ]["stops_after" ])
256
- assert .Equal (t , ws [2 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ), parsed [2 ]["stops_next" ])
249
+ assert .Equal (t , ws [2 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ), parsed [2 ]["stops_next" ])
257
250
// 4th workspace: d-member-ws4 has neither autostart nor autostop enabled.
258
251
assert .Equal (t , ws [3 ].OwnerName + "/" + ws [3 ].Name , parsed [3 ]["workspace" ])
259
252
assert .Empty (t , parsed [3 ]["starts_at" ])
@@ -262,18 +255,20 @@ func TestScheduleShow(t *testing.T) {
262
255
})
263
256
}
264
257
258
+ //nolint:paralleltest // t.Setenv
265
259
func TestScheduleModify (t * testing.T ) {
266
- t .Parallel ()
267
-
268
260
// Given
261
+ // Set timezone to Asia/Kolkata to surface any timezone-related bugs.
262
+ t .Setenv ("TZ" , "Asia/Kolkata" )
263
+ loc , err := tz .TimezoneIANA ()
264
+ require .NoError (t , err )
265
+ require .Equal (t , "Asia/Kolkata" , loc .String ())
269
266
sched , err := cron .Weekly ("CRON_TZ=Europe/Dublin 30 7 * * Mon-Fri" )
270
267
require .NoError (t , err , "invalid schedule" )
271
268
ownerClient , _ , _ , ws := setupTestSchedule (t , sched )
272
269
now := time .Now ()
273
270
274
271
t .Run ("SetStart" , func (t * testing.T ) {
275
- t .Parallel ()
276
-
277
272
// When: we set the start schedule
278
273
inv , root := clitest .New (t ,
279
274
"schedule" , "start" , ws [3 ].OwnerName + "/" + ws [3 ].Name , "7:30AM" , "Mon-Fri" , "Europe/Dublin" ,
@@ -286,12 +281,10 @@ func TestScheduleModify(t *testing.T) {
286
281
// Then: the updated schedule should be shown
287
282
pty .ExpectMatch (ws [3 ].OwnerName + "/" + ws [3 ].Name )
288
283
pty .ExpectMatch (sched .Humanize ())
289
- pty .ExpectMatch (sched .Next (now ).Format (time .RFC3339 ))
284
+ pty .ExpectMatch (sched .Next (now ).In ( loc ). Format (time .RFC3339 ))
290
285
})
291
286
292
287
t .Run ("SetStop" , func (t * testing.T ) {
293
- t .Parallel ()
294
-
295
288
// When: we set the stop schedule
296
289
inv , root := clitest .New (t ,
297
290
"schedule" , "stop" , ws [2 ].OwnerName + "/" + ws [2 ].Name , "8h30m" ,
@@ -304,12 +297,10 @@ func TestScheduleModify(t *testing.T) {
304
297
// Then: the updated schedule should be shown
305
298
pty .ExpectMatch (ws [2 ].OwnerName + "/" + ws [2 ].Name )
306
299
pty .ExpectMatch ("8h30m" )
307
- pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .Format (time .RFC3339 ))
300
+ pty .ExpectMatch (ws [2 ].LatestBuild .Deadline .Time .In ( loc ). Format (time .RFC3339 ))
308
301
})
309
302
310
303
t .Run ("UnsetStart" , func (t * testing.T ) {
311
- t .Parallel ()
312
-
313
304
// When: we unset the start schedule
314
305
inv , root := clitest .New (t ,
315
306
"schedule" , "start" , ws [1 ].OwnerName + "/" + ws [1 ].Name , "manual" ,
@@ -324,8 +315,6 @@ func TestScheduleModify(t *testing.T) {
324
315
})
325
316
326
317
t .Run ("UnsetStop" , func (t * testing.T ) {
327
- t .Parallel ()
328
-
329
318
// When: we unset the stop schedule
330
319
inv , root := clitest .New (t ,
331
320
"schedule" , "stop" , ws [0 ].OwnerName + "/" + ws [0 ].Name , "manual" ,
@@ -340,10 +329,14 @@ func TestScheduleModify(t *testing.T) {
340
329
})
341
330
}
342
331
332
+ //nolint:paralleltest // t.Setenv
343
333
func TestScheduleOverride (t * testing.T ) {
344
- t .Parallel ()
345
-
346
334
// Given
335
+ // Set timezone to Asia/Kolkata to surface any timezone-related bugs.
336
+ t .Setenv ("TZ" , "Asia/Kolkata" )
337
+ loc , err := tz .TimezoneIANA ()
338
+ require .NoError (t , err )
339
+ require .Equal (t , "Asia/Kolkata" , loc .String ())
347
340
sched , err := cron .Weekly ("CRON_TZ=Europe/Dublin 30 7 * * Mon-Fri" )
348
341
require .NoError (t , err , "invalid schedule" )
349
342
ownerClient , _ , _ , ws := setupTestSchedule (t , sched )
@@ -363,7 +356,7 @@ func TestScheduleOverride(t *testing.T) {
363
356
// Then: the updated schedule should be shown
364
357
pty .ExpectMatch (ws [0 ].OwnerName + "/" + ws [0 ].Name )
365
358
pty .ExpectMatch (sched .Humanize ())
366
- pty .ExpectMatch (sched .Next (now ).Format (time .RFC3339 ))
359
+ pty .ExpectMatch (sched .Next (now ).In ( loc ). Format (time .RFC3339 ))
367
360
pty .ExpectMatch ("8h" )
368
361
pty .ExpectMatch (expectedDeadline )
369
362
}
0 commit comments