@@ -16,6 +16,7 @@ import (
16
16
"github.com/coder/coder/v2/coderd/database/dbgen"
17
17
"github.com/coder/coder/v2/coderd/database/dbtestutil"
18
18
agplschedule "github.com/coder/coder/v2/coderd/schedule"
19
+ "github.com/coder/coder/v2/coderd/util/ptr"
19
20
"github.com/coder/coder/v2/cryptorand"
20
21
"github.com/coder/coder/v2/enterprise/coderd/schedule"
21
22
"github.com/coder/coder/v2/testutil"
@@ -27,30 +28,35 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
27
28
db , _ := dbtestutil .NewDB (t )
28
29
29
30
var (
30
- org = dbgen .Organization (t , db , database.Organization {})
31
- user = dbgen .User (t , db , database.User {})
31
+ org = dbgen .Organization (t , db , database.Organization {})
32
+ quietUser = dbgen .User (t , db , database.User {
33
+ Username : "quiet" ,
34
+ })
35
+ noQuietUser = dbgen .User (t , db , database.User {
36
+ Username : "no-quiet" ,
37
+ })
32
38
file = dbgen .File (t , db , database.File {
33
- CreatedBy : user .ID ,
39
+ CreatedBy : quietUser .ID ,
34
40
})
35
41
templateJob = dbgen .ProvisionerJob (t , db , nil , database.ProvisionerJob {
36
42
OrganizationID : org .ID ,
37
43
FileID : file .ID ,
38
- InitiatorID : user .ID ,
44
+ InitiatorID : quietUser .ID ,
39
45
Tags : database.StringMap {
40
46
"foo" : "bar" ,
41
47
},
42
48
})
43
49
templateVersion = dbgen .TemplateVersion (t , db , database.TemplateVersion {
44
50
OrganizationID : org .ID ,
45
- CreatedBy : user .ID ,
51
+ CreatedBy : quietUser .ID ,
46
52
JobID : templateJob .ID ,
47
53
})
48
54
)
49
55
50
56
const userQuietHoursSchedule = "CRON_TZ=UTC 0 0 * * *" // midnight UTC
51
57
ctx := testutil .Context (t , testutil .WaitLong )
52
- user , err := db .UpdateUserQuietHoursSchedule (ctx , database.UpdateUserQuietHoursScheduleParams {
53
- ID : user .ID ,
58
+ quietUser , err := db .UpdateUserQuietHoursSchedule (ctx , database.UpdateUserQuietHoursScheduleParams {
59
+ ID : quietUser .ID ,
54
60
QuietHoursSchedule : userQuietHoursSchedule ,
55
61
})
56
62
require .NoError (t , err )
@@ -62,20 +68,23 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
62
68
63
69
// Workspace old max_deadline too soon
64
70
cases := []struct {
65
- name string
66
- now time.Time
67
- deadline time.Time
68
- maxDeadline time.Time
69
- newDeadline time.Time // 0 for no change
71
+ name string
72
+ now time.Time
73
+ deadline time.Time
74
+ maxDeadline time.Time
75
+ // Set to nil for no change.
76
+ newDeadline * time.Time
70
77
newMaxDeadline time.Time
78
+ noQuietHours bool
79
+ autostopReq * agplschedule.TemplateAutostopRequirement
71
80
}{
72
81
{
73
82
name : "SkippedWorkspaceMaxDeadlineTooSoon" ,
74
83
now : buildTime ,
75
84
deadline : buildTime ,
76
85
maxDeadline : buildTime .Add (1 * time .Hour ),
77
86
// Unchanged since the max deadline is too soon.
78
- newDeadline : time. Time {} ,
87
+ newDeadline : nil ,
79
88
newMaxDeadline : buildTime .Add (1 * time .Hour ),
80
89
},
81
90
{
@@ -85,7 +94,7 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
85
94
deadline : buildTime ,
86
95
// Far into the future...
87
96
maxDeadline : nextQuietHours .Add (24 * time .Hour ),
88
- newDeadline : time. Time {} ,
97
+ newDeadline : nil ,
89
98
// We will use now() + 2 hours if the newly calculated max deadline
90
99
// from the workspace build time is before now.
91
100
newMaxDeadline : nextQuietHours .Add (8 * time .Hour ),
@@ -97,7 +106,7 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
97
106
deadline : buildTime ,
98
107
// Far into the future...
99
108
maxDeadline : nextQuietHours .Add (24 * time .Hour ),
100
- newDeadline : time. Time {} ,
109
+ newDeadline : nil ,
101
110
// We will use now() + 2 hours if the newly calculated max deadline
102
111
// from the workspace build time is within the next 2 hours.
103
112
newMaxDeadline : nextQuietHours .Add (1 * time .Hour ),
@@ -109,7 +118,7 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
109
118
deadline : buildTime ,
110
119
// Far into the future...
111
120
maxDeadline : nextQuietHours .Add (24 * time .Hour ),
112
- newDeadline : time. Time {} ,
121
+ newDeadline : nil ,
113
122
newMaxDeadline : nextQuietHours ,
114
123
},
115
124
{
@@ -120,7 +129,56 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
120
129
deadline : nextQuietHours .Add (24 * time .Hour ),
121
130
maxDeadline : nextQuietHours .Add (24 * time .Hour ),
122
131
// The deadline should match since it is after the new max deadline.
123
- newDeadline : nextQuietHours ,
132
+ newDeadline : ptr .Ref (nextQuietHours ),
133
+ newMaxDeadline : nextQuietHours ,
134
+ },
135
+ {
136
+ // There was a bug if a user has no quiet hours set, and autostop
137
+ // req is not turned on, then the max deadline is set to `time.Time{}`.
138
+ // This zero value was "in the past", so the workspace deadline would
139
+ // be set to "now" + 2 hours.
140
+ // This is a mistake because the max deadline being zero means
141
+ // there is no max deadline.
142
+ name : "MaxDeadlineShouldBeUnset" ,
143
+ now : buildTime ,
144
+ deadline : buildTime .Add (time .Hour * 8 ),
145
+ maxDeadline : time.Time {}, // No max set
146
+ // Should be unchanged
147
+ newDeadline : ptr .Ref (buildTime .Add (time .Hour * 8 )),
148
+ newMaxDeadline : time.Time {},
149
+ noQuietHours : true ,
150
+ autostopReq : & agplschedule.TemplateAutostopRequirement {
151
+ DaysOfWeek : 0 ,
152
+ Weeks : 0 ,
153
+ },
154
+ },
155
+ {
156
+ // A bug existed where MaxDeadline could be set, but deadline was
157
+ // `time.Time{}`. This is a logical inconsistency because the "max"
158
+ // deadline was ignored.
159
+ name : "NoDeadline" ,
160
+ now : buildTime ,
161
+ deadline : time.Time {},
162
+ maxDeadline : time.Time {}, // No max set
163
+ // Should be unchanged
164
+ newDeadline : ptr .Ref (time.Time {}),
165
+ newMaxDeadline : time.Time {},
166
+ noQuietHours : true ,
167
+ autostopReq : & agplschedule.TemplateAutostopRequirement {
168
+ DaysOfWeek : 0 ,
169
+ Weeks : 0 ,
170
+ },
171
+ },
172
+
173
+ {
174
+ // Similar to 'NoDeadline' test. This has a MaxDeadline set, so
175
+ // the deadline of the workspace should now be set.
176
+ name : "WorkspaceDeadlineNowSet" ,
177
+ now : nextQuietHours .Add (- 6 * time .Hour ),
178
+ // Start with unset times
179
+ deadline : time.Time {},
180
+ maxDeadline : time.Time {},
181
+ newDeadline : ptr .Ref (nextQuietHours ),
124
182
newMaxDeadline : nextQuietHours ,
125
183
},
126
184
}
@@ -131,6 +189,11 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
131
189
t .Run (c .name , func (t * testing.T ) {
132
190
t .Parallel ()
133
191
192
+ user := quietUser
193
+ if c .noQuietHours {
194
+ user = noQuietUser
195
+ }
196
+
134
197
t .Log ("buildTime" , buildTime )
135
198
t .Log ("nextQuietHours" , nextQuietHours )
136
199
t .Log ("now" , c .now )
@@ -217,17 +280,22 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
217
280
templateScheduleStore .TimeNowFn = func () time.Time {
218
281
return c .now
219
282
}
283
+
284
+ autostopReq := agplschedule.TemplateAutostopRequirement {
285
+ // Every day
286
+ DaysOfWeek : 0b01111111 ,
287
+ Weeks : 0 ,
288
+ }
289
+ if c .autostopReq != nil {
290
+ autostopReq = * c .autostopReq
291
+ }
220
292
_ , err = templateScheduleStore .Set (ctx , db , template , agplschedule.TemplateScheduleOptions {
221
- UserAutostartEnabled : false ,
222
- UserAutostopEnabled : false ,
223
- DefaultTTL : 0 ,
224
- MaxTTL : 0 ,
225
- UseMaxTTL : false ,
226
- AutostopRequirement : agplschedule.TemplateAutostopRequirement {
227
- // Every day
228
- DaysOfWeek : 0b01111111 ,
229
- Weeks : 0 ,
230
- },
293
+ UserAutostartEnabled : false ,
294
+ UserAutostopEnabled : false ,
295
+ DefaultTTL : 0 ,
296
+ MaxTTL : 0 ,
297
+ UseMaxTTL : false ,
298
+ AutostopRequirement : autostopReq ,
231
299
FailureTTL : 0 ,
232
300
TimeTilDormant : 0 ,
233
301
TimeTilDormantAutoDelete : 0 ,
@@ -238,10 +306,10 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
238
306
newBuild , err := db .GetWorkspaceBuildByID (ctx , wsBuild .ID )
239
307
require .NoError (t , err )
240
308
241
- if c .newDeadline . IsZero () {
242
- c .newDeadline = wsBuild .Deadline
309
+ if c .newDeadline == nil {
310
+ c .newDeadline = & wsBuild .Deadline
243
311
}
244
- require .WithinDuration (t , c .newDeadline , newBuild .Deadline , time .Second )
312
+ require .WithinDuration (t , * c .newDeadline , newBuild .Deadline , time .Second )
245
313
require .WithinDuration (t , c .newMaxDeadline , newBuild .MaxDeadline , time .Second )
246
314
247
315
// Check that the new build has the same state as before.
0 commit comments