@@ -736,6 +736,65 @@ func TestWorkspaceAutobuild(t *testing.T) {
736
736
})
737
737
}
738
738
739
+ // Blocked by autostart requirements
740
+ func TestExecutorAutostartBlocked (t * testing.T ) {
741
+ t .Parallel ()
742
+
743
+ now := time .Now ()
744
+ var allowed []string
745
+ for _ ,day := range agplschedule .DaysOfWeek {
746
+ // Skip the day the workspace was created on and if the next day is within 2
747
+ // hours, skip that too. The cron scheduler will start the workspace every hour,
748
+ // so it can span into the next day.
749
+ if day != now .UTC ().Weekday ()&&
750
+ day != now .UTC ().Add (time .Hour * 2 ).Weekday () {
751
+ allowed = append (allowed ,day .String ())
752
+ }
753
+ }
754
+
755
+ var (
756
+ sched = must (cron .Weekly ("CRON_TZ=UTC 0 * * * *" ))
757
+ tickCh = make (chan time.Time )
758
+ statsCh = make (chan autobuild.Stats )
759
+ client ,owner = coderdenttest .New (t ,& coderdenttest.Options {
760
+ Options :& coderdtest.Options {
761
+ AutobuildTicker :tickCh ,
762
+ IncludeProvisionerDaemon :true ,
763
+ AutobuildStats :statsCh ,
764
+ TemplateScheduleStore :schedule .NewEnterpriseTemplateScheduleStore (agplUserQuietHoursScheduleStore ()),
765
+ },
766
+ LicenseOptions :& coderdenttest.LicenseOptions {
767
+ Features : license.Features {codersdk .FeatureAdvancedTemplateScheduling :1 },
768
+ },
769
+ })
770
+ version = coderdtest .CreateTemplateVersion (t ,client ,owner .OrganizationID ,nil )
771
+ template = coderdtest .CreateTemplate (t ,client ,owner .OrganizationID ,version .ID ,func (request * codersdk.CreateTemplateRequest ) {
772
+ request .AutostartRequirement = & codersdk.TemplateAutostartRequirement {
773
+ DaysOfWeek :allowed ,
774
+ }
775
+ })
776
+ _ = coderdtest .AwaitTemplateVersionJobCompleted (t ,client ,version .ID )
777
+ workspace = coderdtest .CreateWorkspace (t ,client ,owner .OrganizationID ,template .ID ,func (cwr * codersdk.CreateWorkspaceRequest ) {
778
+ cwr .AutostartSchedule = ptr .Ref (sched .String ())
779
+ })
780
+ _ = coderdtest .AwaitWorkspaceBuildJobCompleted (t ,client ,workspace .LatestBuild .ID )
781
+ )
782
+
783
+ // Given: workspace is stopped
784
+ workspace = coderdtest .MustTransitionWorkspace (t ,client ,workspace .ID ,database .WorkspaceTransitionStart ,database .WorkspaceTransitionStop )
785
+
786
+ // When: the autobuild executor ticks way into the future
787
+ go func () {
788
+ tickCh <- workspace .LatestBuild .CreatedAt .Add (24 * time .Hour )
789
+ close (tickCh )
790
+ }()
791
+
792
+ // Then: the workspace should not be started.
793
+ stats := <- statsCh
794
+ require .NoError (t ,stats .Error )
795
+ require .Len (t ,stats .Transitions ,0 )
796
+ }
797
+
739
798
func TestWorkspacesFiltering (t * testing.T ) {
740
799
t .Parallel ()
741
800
@@ -911,3 +970,10 @@ func TestWorkspaceLock(t *testing.T) {
911
970
require .True (t ,workspace .LastUsedAt .After (lastUsedAt ))
912
971
})
913
972
}
973
+
974
+ func must [T any ](value T ,err error )T {
975
+ if err != nil {
976
+ panic (err )
977
+ }
978
+ return value
979
+ }