@@ -428,6 +428,147 @@ func TestTemplateEdit(t *testing.T) {
428
428
429
429
require.EqualValues(t, 1, atomic.LoadInt64(&updateTemplateCalled))
430
430
431
+ // Assert that the template metadata did not change. We verify the
432
+ // correct request gets sent to the server already.
433
+ updated, err := client.Template(context.Background(), template.ID)
434
+ require.NoError(t, err)
435
+ assert.Equal(t, template.Name, updated.Name)
436
+ assert.Equal(t, template.Description, updated.Description)
437
+ assert.Equal(t, template.Icon, updated.Icon)
438
+ assert.Equal(t, template.DisplayName, updated.DisplayName)
439
+ assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
440
+ assert.Equal(t, template.MaxTTLMillis, updated.MaxTTLMillis)
441
+ })
442
+ })
443
+ t.Run("AllowUserScheduling", func(t *testing.T) {
444
+ t.Parallel()
445
+ t.Run("BlockedAGPL", func(t *testing.T) {
446
+ t.Parallel()
447
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
448
+ user := coderdtest.CreateFirstUser(t, client)
449
+ version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
450
+ _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
451
+ template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
452
+ ctr.DefaultTTLMillis = nil
453
+ ctr.MaxTTLMillis = nil
454
+ })
455
+
456
+ // Test the cli command with --allow-user-autostart.
457
+ cmdArgs := []string{
458
+ "templates",
459
+ "edit",
460
+ template.Name,
461
+ "--allow-user-autostart=false",
462
+ }
463
+ inv, root := clitest.New(t, cmdArgs...)
464
+ clitest.SetupConfig(t, client, root)
465
+
466
+ ctx := testutil.Context(t, testutil.WaitLong)
467
+ err := inv.WithContext(ctx).Run()
468
+ require.Error(t, err)
469
+ require.ErrorContains(t, err, "appears to be an AGPL deployment")
470
+
471
+ // Test the cli command with --allow-user-autostop.
472
+ cmdArgs = []string{
473
+ "templates",
474
+ "edit",
475
+ template.Name,
476
+ "--allow-user-autostop=false",
477
+ }
478
+ inv, root = clitest.New(t, cmdArgs...)
479
+ clitest.SetupConfig(t, client, root)
480
+
481
+ ctx = testutil.Context(t, testutil.WaitLong)
482
+ err = inv.WithContext(ctx).Run()
483
+ require.Error(t, err)
484
+ require.ErrorContains(t, err, "appears to be an AGPL deployment")
485
+
486
+ // Assert that the template metadata did not change.
487
+ updated, err := client.Template(context.Background(), template.ID)
488
+ require.NoError(t, err)
489
+ assert.Equal(t, template.Name, updated.Name)
490
+ assert.Equal(t, template.Description, updated.Description)
491
+ assert.Equal(t, template.Icon, updated.Icon)
492
+ assert.Equal(t, template.DisplayName, updated.DisplayName)
493
+ assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
494
+ assert.Equal(t, template.MaxTTLMillis, updated.MaxTTLMillis)
495
+ assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
496
+ assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
497
+ })
498
+
499
+ t.Run("BlockedNotEntitled", func(t *testing.T) {
500
+ t.Parallel()
501
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
502
+ user := coderdtest.CreateFirstUser(t, client)
503
+ version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
504
+ _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
505
+ template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
506
+
507
+ // Make a proxy server that will return a valid entitlements
508
+ // response, but without advanced scheduling entitlement.
509
+ proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
510
+ if r.URL.Path == "/api/v2/entitlements" {
511
+ res := codersdk.Entitlements{
512
+ Features: map[codersdk.FeatureName]codersdk.Feature{},
513
+ Warnings: []string{},
514
+ Errors: []string{},
515
+ HasLicense: true,
516
+ Trial: true,
517
+ RequireTelemetry: false,
518
+ }
519
+ for _, feature := range codersdk.FeatureNames {
520
+ res.Features[feature] = codersdk.Feature{
521
+ Entitlement: codersdk.EntitlementNotEntitled,
522
+ Enabled: false,
523
+ Limit: nil,
524
+ Actual: nil,
525
+ }
526
+ }
527
+ httpapi.Write(r.Context(), w, http.StatusOK, res)
528
+ return
529
+ }
530
+
531
+ // Otherwise, proxy the request to the real API server.
532
+ httputil.NewSingleHostReverseProxy(client.URL).ServeHTTP(w, r)
533
+ }))
534
+ defer proxy.Close()
535
+
536
+ // Create a new client that uses the proxy server.
537
+ proxyURL, err := url.Parse(proxy.URL)
538
+ require.NoError(t, err)
539
+ proxyClient := codersdk.New(proxyURL)
540
+ proxyClient.SetSessionToken(client.SessionToken())
541
+
542
+ // Test the cli command with --allow-user-autostart.
543
+ cmdArgs := []string{
544
+ "templates",
545
+ "edit",
546
+ template.Name,
547
+ "--allow-user-autostart=false",
548
+ }
549
+ inv, root := clitest.New(t, cmdArgs...)
550
+ clitest.SetupConfig(t, proxyClient, root)
551
+
552
+ ctx := testutil.Context(t, testutil.WaitLong)
553
+ err = inv.WithContext(ctx).Run()
554
+ require.Error(t, err)
555
+ require.ErrorContains(t, err, "license is not entitled")
556
+
557
+ // Test the cli command with --allow-user-autostop.
558
+ cmdArgs = []string{
559
+ "templates",
560
+ "edit",
561
+ template.Name,
562
+ "--allow-user-autostop=false",
563
+ }
564
+ inv, root = clitest.New(t, cmdArgs...)
565
+ clitest.SetupConfig(t, proxyClient, root)
566
+
567
+ ctx = testutil.Context(t, testutil.WaitLong)
568
+ err = inv.WithContext(ctx).Run()
569
+ require.Error(t, err)
570
+ require.ErrorContains(t, err, "license is not entitled")
571
+
431
572
// Assert that the template metadata did not change.
432
573
updated, err := client.Template(context.Background(), template.ID)
433
574
require.NoError(t, err)
@@ -437,6 +578,98 @@ func TestTemplateEdit(t *testing.T) {
437
578
assert.Equal(t, template.DisplayName, updated.DisplayName)
438
579
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
439
580
assert.Equal(t, template.MaxTTLMillis, updated.MaxTTLMillis)
581
+ assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
582
+ assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
583
+ })
584
+ t.Run("Entitled", func(t *testing.T) {
585
+ t.Parallel()
586
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
587
+ user := coderdtest.CreateFirstUser(t, client)
588
+ version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
589
+ _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
590
+ template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
591
+
592
+ // Make a proxy server that will return a valid entitlements
593
+ // response, including a valid advanced scheduling entitlement.
594
+ var updateTemplateCalled int64
595
+ proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
596
+ if r.URL.Path == "/api/v2/entitlements" {
597
+ res := codersdk.Entitlements{
598
+ Features: map[codersdk.FeatureName]codersdk.Feature{},
599
+ Warnings: []string{},
600
+ Errors: []string{},
601
+ HasLicense: true,
602
+ Trial: true,
603
+ RequireTelemetry: false,
604
+ }
605
+ for _, feature := range codersdk.FeatureNames {
606
+ var one int64 = 1
607
+ res.Features[feature] = codersdk.Feature{
608
+ Entitlement: codersdk.EntitlementNotEntitled,
609
+ Enabled: true,
610
+ Limit: &one,
611
+ Actual: &one,
612
+ }
613
+ }
614
+ httpapi.Write(r.Context(), w, http.StatusOK, res)
615
+ return
616
+ }
617
+ if strings.HasPrefix(r.URL.Path, "/api/v2/templates/") {
618
+ body, err := io.ReadAll(r.Body)
619
+ require.NoError(t, err)
620
+ _ = r.Body.Close()
621
+
622
+ var req codersdk.UpdateTemplateMeta
623
+ err = json.Unmarshal(body, &req)
624
+ require.NoError(t, err)
625
+ assert.False(t, req.AllowUserAutostart)
626
+ assert.False(t, req.AllowUserAutostop)
627
+
628
+ r.Body = io.NopCloser(bytes.NewReader(body))
629
+ atomic.AddInt64(&updateTemplateCalled, 1)
630
+ // We still want to call the real route.
631
+ }
632
+
633
+ // Otherwise, proxy the request to the real API server.
634
+ httputil.NewSingleHostReverseProxy(client.URL).ServeHTTP(w, r)
635
+ }))
636
+ defer proxy.Close()
637
+
638
+ // Create a new client that uses the proxy server.
639
+ proxyURL, err := url.Parse(proxy.URL)
640
+ require.NoError(t, err)
641
+ proxyClient := codersdk.New(proxyURL)
642
+ proxyClient.SetSessionToken(client.SessionToken())
643
+
644
+ // Test the cli command.
645
+ cmdArgs := []string{
646
+ "templates",
647
+ "edit",
648
+ template.Name,
649
+ "--allow-user-autostart=false",
650
+ "--allow-user-autostop=false",
651
+ }
652
+ inv, root := clitest.New(t, cmdArgs...)
653
+ clitest.SetupConfig(t, proxyClient, root)
654
+
655
+ ctx := testutil.Context(t, testutil.WaitLong)
656
+ err = inv.WithContext(ctx).Run()
657
+ require.NoError(t, err)
658
+
659
+ require.EqualValues(t, 1, atomic.LoadInt64(&updateTemplateCalled))
660
+
661
+ // Assert that the template metadata did not change. We verify the
662
+ // correct request gets sent to the server already.
663
+ updated, err := client.Template(context.Background(), template.ID)
664
+ require.NoError(t, err)
665
+ assert.Equal(t, template.Name, updated.Name)
666
+ assert.Equal(t, template.Description, updated.Description)
667
+ assert.Equal(t, template.Icon, updated.Icon)
668
+ assert.Equal(t, template.DisplayName, updated.DisplayName)
669
+ assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
670
+ assert.Equal(t, template.MaxTTLMillis, updated.MaxTTLMillis)
671
+ assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
672
+ assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
440
673
})
441
674
})
442
675
}
0 commit comments