1
1
package cli_test
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
6
+ "encoding/json"
7
+ "io"
8
+ "net/http"
9
+ "net/http/httptest"
10
+ "net/http/httputil"
11
+ "net/url"
5
12
"strconv"
13
+ "strings"
14
+ "sync/atomic"
6
15
"testing"
7
16
"time"
8
17
@@ -11,6 +20,7 @@ import (
11
20
12
21
"github.com/coder/coder/cli/clitest"
13
22
"github.com/coder/coder/coderd/coderdtest"
23
+ "github.com/coder/coder/coderd/httpapi"
14
24
"github.com/coder/coder/codersdk"
15
25
"github.com/coder/coder/testutil"
16
26
)
@@ -230,4 +240,205 @@ func TestTemplateEdit(t *testing.T) {
230
240
assert .Equal (t , "" , updated .Icon )
231
241
assert .Equal (t , "" , updated .DisplayName )
232
242
})
243
+ t .Run ("MaxTTL" , func (t * testing.T ) {
244
+ t .Parallel ()
245
+ t .Run ("BlockedAGPL" , func (t * testing.T ) {
246
+ t .Parallel ()
247
+ client := coderdtest .New (t , & coderdtest.Options {IncludeProvisionerDaemon : true })
248
+ user := coderdtest .CreateFirstUser (t , client )
249
+ version := coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , nil )
250
+ _ = coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
251
+ template := coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID , func (ctr * codersdk.CreateTemplateRequest ) {
252
+ ctr .DefaultTTLMillis = nil
253
+ ctr .MaxTTLMillis = nil
254
+ })
255
+
256
+ // Test the cli command.
257
+ cmdArgs := []string {
258
+ "templates" ,
259
+ "edit" ,
260
+ template .Name ,
261
+ "--max-ttl" , "1h" ,
262
+ }
263
+ cmd , root := clitest .New (t , cmdArgs ... )
264
+ clitest .SetupConfig (t , client , root )
265
+
266
+ ctx , _ := testutil .Context (t )
267
+ err := cmd .ExecuteContext (ctx )
268
+ require .Error (t , err )
269
+ require .ErrorContains (t , err , "appears to be an AGPL deployment" )
270
+
271
+ // Assert that the template metadata did not change.
272
+ updated , err := client .Template (context .Background (), template .ID )
273
+ require .NoError (t , err )
274
+ assert .Equal (t , template .Name , updated .Name )
275
+ assert .Equal (t , template .Description , updated .Description )
276
+ assert .Equal (t , template .Icon , updated .Icon )
277
+ assert .Equal (t , template .DisplayName , updated .DisplayName )
278
+ assert .Equal (t , template .DefaultTTLMillis , updated .DefaultTTLMillis )
279
+ assert .Equal (t , template .MaxTTLMillis , updated .MaxTTLMillis )
280
+ })
281
+
282
+ t .Run ("BlockedNotEntitled" , func (t * testing.T ) {
283
+ t .Parallel ()
284
+ client := coderdtest .New (t , & coderdtest.Options {IncludeProvisionerDaemon : true })
285
+ user := coderdtest .CreateFirstUser (t , client )
286
+ version := coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , nil )
287
+ _ = coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
288
+ template := coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID , func (ctr * codersdk.CreateTemplateRequest ) {
289
+ ctr .DefaultTTLMillis = nil
290
+ ctr .MaxTTLMillis = nil
291
+ })
292
+
293
+ // Make a proxy server that will return a valid entitlements
294
+ // response, but without advanced scheduling entitlement.
295
+ proxy := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
296
+ if r .URL .Path == "/api/v2/entitlements" {
297
+ res := codersdk.Entitlements {
298
+ Features : map [codersdk.FeatureName ]codersdk.Feature {},
299
+ Warnings : []string {},
300
+ Errors : []string {},
301
+ HasLicense : true ,
302
+ Trial : true ,
303
+ RequireTelemetry : false ,
304
+ Experimental : false ,
305
+ }
306
+ for _ , feature := range codersdk .FeatureNames {
307
+ res .Features [feature ] = codersdk.Feature {
308
+ Entitlement : codersdk .EntitlementNotEntitled ,
309
+ Enabled : false ,
310
+ Limit : nil ,
311
+ Actual : nil ,
312
+ }
313
+ }
314
+ httpapi .Write (r .Context (), w , http .StatusOK , res )
315
+ return
316
+ }
317
+
318
+ // Otherwise, proxy the request to the real API server.
319
+ httputil .NewSingleHostReverseProxy (client .URL ).ServeHTTP (w , r )
320
+ }))
321
+ defer proxy .Close ()
322
+
323
+ // Create a new client that uses the proxy server.
324
+ proxyURL , err := url .Parse (proxy .URL )
325
+ require .NoError (t , err )
326
+ proxyClient := codersdk .New (proxyURL )
327
+ proxyClient .SetSessionToken (client .SessionToken ())
328
+
329
+ // Test the cli command.
330
+ cmdArgs := []string {
331
+ "templates" ,
332
+ "edit" ,
333
+ template .Name ,
334
+ "--max-ttl" , "1h" ,
335
+ }
336
+ cmd , root := clitest .New (t , cmdArgs ... )
337
+ clitest .SetupConfig (t , proxyClient , root )
338
+
339
+ ctx , _ := testutil .Context (t )
340
+ err = cmd .ExecuteContext (ctx )
341
+ require .Error (t , err )
342
+ require .ErrorContains (t , err , "license is not entitled" )
343
+
344
+ // Assert that the template metadata did not change.
345
+ updated , err := client .Template (context .Background (), template .ID )
346
+ require .NoError (t , err )
347
+ assert .Equal (t , template .Name , updated .Name )
348
+ assert .Equal (t , template .Description , updated .Description )
349
+ assert .Equal (t , template .Icon , updated .Icon )
350
+ assert .Equal (t , template .DisplayName , updated .DisplayName )
351
+ assert .Equal (t , template .DefaultTTLMillis , updated .DefaultTTLMillis )
352
+ assert .Equal (t , template .MaxTTLMillis , updated .MaxTTLMillis )
353
+ })
354
+ t .Run ("Entitled" , func (t * testing.T ) {
355
+ t .Parallel ()
356
+ client := coderdtest .New (t , & coderdtest.Options {IncludeProvisionerDaemon : true })
357
+ user := coderdtest .CreateFirstUser (t , client )
358
+ version := coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , nil )
359
+ _ = coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
360
+ template := coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID , func (ctr * codersdk.CreateTemplateRequest ) {
361
+ ctr .DefaultTTLMillis = nil
362
+ ctr .MaxTTLMillis = nil
363
+ })
364
+
365
+ // Make a proxy server that will return a valid entitlements
366
+ // response, including a valid advanced scheduling entitlement.
367
+ var updateTemplateCalled int64
368
+ proxy := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
369
+ if r .URL .Path == "/api/v2/entitlements" {
370
+ res := codersdk.Entitlements {
371
+ Features : map [codersdk.FeatureName ]codersdk.Feature {},
372
+ Warnings : []string {},
373
+ Errors : []string {},
374
+ HasLicense : true ,
375
+ Trial : true ,
376
+ RequireTelemetry : false ,
377
+ Experimental : false ,
378
+ }
379
+ for _ , feature := range codersdk .FeatureNames {
380
+ var one int64 = 1
381
+ res .Features [feature ] = codersdk.Feature {
382
+ Entitlement : codersdk .EntitlementNotEntitled ,
383
+ Enabled : true ,
384
+ Limit : & one ,
385
+ Actual : & one ,
386
+ }
387
+ }
388
+ httpapi .Write (r .Context (), w , http .StatusOK , res )
389
+ return
390
+ }
391
+ if strings .HasPrefix (r .URL .Path , "/api/v2/templates/" ) {
392
+ body , err := io .ReadAll (r .Body )
393
+ require .NoError (t , err )
394
+ _ = r .Body .Close ()
395
+
396
+ var req codersdk.UpdateTemplateMeta
397
+ err = json .Unmarshal (body , & req )
398
+ require .NoError (t , err )
399
+ assert .Equal (t , time .Hour .Milliseconds (), req .MaxTTLMillis )
400
+
401
+ r .Body = io .NopCloser (bytes .NewReader (body ))
402
+ atomic .AddInt64 (& updateTemplateCalled , 1 )
403
+ // We still want to call the real route.
404
+ }
405
+
406
+ // Otherwise, proxy the request to the real API server.
407
+ httputil .NewSingleHostReverseProxy (client .URL ).ServeHTTP (w , r )
408
+ }))
409
+ defer proxy .Close ()
410
+
411
+ // Create a new client that uses the proxy server.
412
+ proxyURL , err := url .Parse (proxy .URL )
413
+ require .NoError (t , err )
414
+ proxyClient := codersdk .New (proxyURL )
415
+ proxyClient .SetSessionToken (client .SessionToken ())
416
+
417
+ // Test the cli command.
418
+ cmdArgs := []string {
419
+ "templates" ,
420
+ "edit" ,
421
+ template .Name ,
422
+ "--max-ttl" , "1h" ,
423
+ }
424
+ cmd , root := clitest .New (t , cmdArgs ... )
425
+ clitest .SetupConfig (t , proxyClient , root )
426
+
427
+ ctx , _ := testutil .Context (t )
428
+ err = cmd .ExecuteContext (ctx )
429
+ require .NoError (t , err )
430
+
431
+ require .EqualValues (t , 1 , atomic .LoadInt64 (& updateTemplateCalled ))
432
+
433
+ // Assert that the template metadata did not change.
434
+ updated , err := client .Template (context .Background (), template .ID )
435
+ require .NoError (t , err )
436
+ assert .Equal (t , template .Name , updated .Name )
437
+ assert .Equal (t , template .Description , updated .Description )
438
+ assert .Equal (t , template .Icon , updated .Icon )
439
+ assert .Equal (t , template .DisplayName , updated .DisplayName )
440
+ assert .Equal (t , template .DefaultTTLMillis , updated .DefaultTTLMillis )
441
+ assert .Equal (t , template .MaxTTLMillis , updated .MaxTTLMillis )
442
+ })
443
+ })
233
444
}
0 commit comments