@@ -84,7 +84,7 @@ func TestNoPrebuilds(t *testing.T) {
84
84
preset (true ,0 ,current ),
85
85
}
86
86
87
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,nil ,nil ,nil ,nil )
87
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,nil ,nil ,nil ,nil , quartz . NewMock ( t ) )
88
88
ps ,err := snapshot .FilterByPreset (current .presetID )
89
89
require .NoError (t ,err )
90
90
@@ -106,7 +106,7 @@ func TestNetNew(t *testing.T) {
106
106
preset (true ,1 ,current ),
107
107
}
108
108
109
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,nil ,nil ,nil ,nil )
109
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,nil ,nil ,nil ,nil , quartz . NewMock ( t ) )
110
110
ps ,err := snapshot .FilterByPreset (current .presetID )
111
111
require .NoError (t ,err )
112
112
@@ -148,7 +148,7 @@ func TestOutdatedPrebuilds(t *testing.T) {
148
148
var inProgress []database.CountInProgressPrebuildsRow
149
149
150
150
// WHEN: calculating the outdated preset's state.
151
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil )
151
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil , quartz . NewMock ( t ) )
152
152
ps ,err := snapshot .FilterByPreset (outdated .presetID )
153
153
require .NoError (t ,err )
154
154
@@ -214,7 +214,7 @@ func TestDeleteOutdatedPrebuilds(t *testing.T) {
214
214
}
215
215
216
216
// WHEN: calculating the outdated preset's state.
217
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil )
217
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil , quartz . NewMock ( t ) )
218
218
ps ,err := snapshot .FilterByPreset (outdated .presetID )
219
219
require .NoError (t ,err )
220
220
@@ -459,7 +459,7 @@ func TestInProgressActions(t *testing.T) {
459
459
}
460
460
461
461
// WHEN: calculating the current preset's state.
462
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil )
462
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil , quartz . NewMock ( t ) )
463
463
ps ,err := snapshot .FilterByPreset (current .presetID )
464
464
require .NoError (t ,err )
465
465
@@ -502,7 +502,7 @@ func TestExtraneous(t *testing.T) {
502
502
var inProgress []database.CountInProgressPrebuildsRow
503
503
504
504
// WHEN: calculating the current preset's state.
505
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil )
505
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil , quartz . NewMock ( t ) )
506
506
ps ,err := snapshot .FilterByPreset (current .presetID )
507
507
require .NoError (t ,err )
508
508
@@ -683,7 +683,7 @@ func TestExpiredPrebuilds(t *testing.T) {
683
683
}
684
684
685
685
// WHEN: calculating the current preset's state.
686
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,nil ,nil ,nil )
686
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,nil ,nil ,nil , quartz . NewMock ( t ) )
687
687
ps ,err := snapshot .FilterByPreset (current .presetID )
688
688
require .NoError (t ,err )
689
689
@@ -719,7 +719,7 @@ func TestDeprecated(t *testing.T) {
719
719
var inProgress []database.CountInProgressPrebuildsRow
720
720
721
721
// WHEN: calculating the current preset's state.
722
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil )
722
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,nil ,nil , quartz . NewMock ( t ) )
723
723
ps ,err := snapshot .FilterByPreset (current .presetID )
724
724
require .NoError (t ,err )
725
725
@@ -772,7 +772,7 @@ func TestLatestBuildFailed(t *testing.T) {
772
772
}
773
773
774
774
// WHEN: calculating the current preset's state.
775
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,backoffs ,nil )
775
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,running ,inProgress ,backoffs ,nil , quartz . NewMock ( t ) )
776
776
psCurrent ,err := snapshot .FilterByPreset (current .presetID )
777
777
require .NoError (t ,err )
778
778
@@ -865,7 +865,7 @@ func TestMultiplePresetsPerTemplateVersion(t *testing.T) {
865
865
},
866
866
}
867
867
868
- snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,nil ,inProgress ,nil ,nil )
868
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,nil ,nil ,inProgress ,nil ,nil , quartz . NewMock ( t ) )
869
869
870
870
// Nothing has to be created for preset 1.
871
871
{
@@ -905,6 +905,91 @@ func TestMultiplePresetsPerTemplateVersion(t *testing.T) {
905
905
}
906
906
}
907
907
908
+ func TestMultiplePresetsPerTemplateVersionV2 (t * testing.T ) {
909
+ t .Parallel ()
910
+
911
+ templateID := uuid .New ()
912
+ templateVersionID := uuid .New ()
913
+ presetOpts1 := options {
914
+ templateID :templateID ,
915
+ templateVersionID :templateVersionID ,
916
+ presetID :uuid .New (),
917
+ presetName :"my-preset-1" ,
918
+ prebuiltWorkspaceID :uuid .New (),
919
+ workspaceName :"prebuilds1" ,
920
+ }
921
+ presetOpts2 := options {
922
+ templateID :templateID ,
923
+ templateVersionID :templateVersionID ,
924
+ presetID :uuid .New (),
925
+ presetName :"my-preset-2" ,
926
+ prebuiltWorkspaceID :uuid .New (),
927
+ workspaceName :"prebuilds2" ,
928
+ }
929
+
930
+ clock := quartz .NewMock (t )
931
+ clock .Set (mustParseTime (t ,time .RFC1123 ,"Mon, 02 Jun 2025 01:00:00 UTC" ))
932
+ enableAutoscaling := func (preset database.GetTemplatePresetsWithPrebuildsRow ) database.GetTemplatePresetsWithPrebuildsRow {
933
+ preset .AutoscalingEnabled = true
934
+ preset .AutoscalingTimezone = "UTC"
935
+ return preset
936
+ }
937
+ presets := []database.GetTemplatePresetsWithPrebuildsRow {
938
+ preset (true ,1 ,presetOpts1 ,enableAutoscaling ),
939
+ preset (true ,1 ,presetOpts2 ,enableAutoscaling ),
940
+ }
941
+ schedules := []database.TemplateVersionPresetPrebuildSchedule {
942
+ schedule (presets [0 ].ID ,"* 2-4 * * 1-5" ,2 ),
943
+ schedule (presets [0 ].ID ,"* 6-8 * * 1-5" ,3 ),
944
+ schedule (presets [1 ].ID ,"* 10-12 * * 1-5" ,4 ),
945
+ schedule (presets [1 ].ID ,"* 14-16 * * 1-5" ,5 ),
946
+ }
947
+
948
+ snapshot := prebuilds .NewGlobalSnapshot (presets ,schedules ,nil ,nil ,nil ,nil ,clock )
949
+
950
+ // Nothing has to be created for preset 1.
951
+ {
952
+ ps ,err := snapshot .FilterByPreset (presetOpts1 .presetID )
953
+ require .NoError (t ,err )
954
+
955
+ state := ps .CalculateState ()
956
+ actions ,err := ps .CalculateActions (clock ,backoffInterval )
957
+ require .NoError (t ,err )
958
+
959
+ validateState (t , prebuilds.ReconciliationState {
960
+ Starting :0 ,
961
+ Desired :1 ,
962
+ },* state )
963
+ validateActions (t , []* prebuilds.ReconciliationActions {
964
+ {
965
+ ActionType :prebuilds .ActionTypeCreate ,
966
+ Create :1 ,
967
+ },
968
+ },actions )
969
+ }
970
+
971
+ // One prebuild has to be created for preset 2. Make sure preset 1 doesn't block preset 2.
972
+ {
973
+ ps ,err := snapshot .FilterByPreset (presetOpts2 .presetID )
974
+ require .NoError (t ,err )
975
+
976
+ state := ps .CalculateState ()
977
+ actions ,err := ps .CalculateActions (clock ,backoffInterval )
978
+ require .NoError (t ,err )
979
+
980
+ validateState (t , prebuilds.ReconciliationState {
981
+ Starting :0 ,
982
+ Desired :1 ,
983
+ },* state )
984
+ validateActions (t , []* prebuilds.ReconciliationActions {
985
+ {
986
+ ActionType :prebuilds .ActionTypeCreate ,
987
+ Create :1 ,
988
+ },
989
+ },actions )
990
+ }
991
+ }
992
+
908
993
func TestMatchesCron (t * testing.T ) {
909
994
t .Parallel ()
910
995
testCases := []struct {
@@ -1294,6 +1379,15 @@ func preset(active bool, instances int32, opts options, muts ...func(row databas
1294
1379
return entry
1295
1380
}
1296
1381
1382
+ func schedule (presetID uuid.UUID ,cronExpr string ,instances int32 ) database.TemplateVersionPresetPrebuildSchedule {
1383
+ return database.TemplateVersionPresetPrebuildSchedule {
1384
+ ID :uuid .New (),
1385
+ PresetID :presetID ,
1386
+ CronExpression :cronExpr ,
1387
+ Instances :instances ,
1388
+ }
1389
+ }
1390
+
1297
1391
func prebuiltWorkspace (
1298
1392
opts options ,
1299
1393
clock quartz.Clock ,