Skip to content

Commit 1a9817b

Browse files
test: added calculate-desired-instances test
1 parent 597056a commit 1a9817b

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

coderd/prebuilds/preset_snapshot.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func MatchesCron(cronExpression string, now time.Time) (bool, error) {
9797
return sched.IsWithinRange(now), nil
9898
}
9999

100-
func (p PresetSnapshot) calculateDesiredInstances(now time.Time) (int32, error) {
100+
func (p PresetSnapshot) CalculateDesiredInstances(now time.Time) (int32, error) {
101101
if !p.Preset.AutoscalingEnabled {
102102
return p.Preset.DesiredInstances.Int32, nil
103103
}
@@ -152,7 +152,7 @@ func (p PresetSnapshot) CalculateState() *ReconciliationState {
152152

153153
if p.isActive() {
154154
var err error
155-
desired, err = p.calculateDesiredInstances(time.Now())
155+
desired, err = p.CalculateDesiredInstances(time.Now())
156156
if err != nil {
157157
// TODO: handle error
158158
}

coderd/prebuilds/preset_snapshot_test.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,151 @@ func TestMatchesCron(t *testing.T) {
941941
}
942942
}
943943

944+
func TestCalculateDesiredInstances(t *testing.T) {
945+
t.Parallel()
946+
947+
mkPreset := func(instances int32, timezone string) database.GetTemplatePresetsWithPrebuildsRow {
948+
return database.GetTemplatePresetsWithPrebuildsRow{
949+
DesiredInstances: sql.NullInt32{
950+
Int32: instances,
951+
Valid: true,
952+
},
953+
AutoscalingEnabled: true,
954+
AutoscalingTimezone: timezone,
955+
}
956+
}
957+
mkSchedule := func(cronExpr string, instances int32) database.TemplateVersionPresetPrebuildSchedule {
958+
return database.TemplateVersionPresetPrebuildSchedule{
959+
CronExpression: cronExpr,
960+
Instances: instances,
961+
}
962+
}
963+
mkSnapshot := func(preset database.GetTemplatePresetsWithPrebuildsRow, schedules ...database.TemplateVersionPresetPrebuildSchedule) prebuilds.PresetSnapshot {
964+
return prebuilds.PresetSnapshot{
965+
Preset: preset,
966+
PrebuildSchedules: schedules,
967+
}
968+
}
969+
970+
testCases := []struct {
971+
name string
972+
snapshot prebuilds.PresetSnapshot
973+
at time.Time
974+
expectedCalculatedInstances int32
975+
}{
976+
// "* 9-18 * * 1-5" should be interpreted as a continuous time range from 08:59:00 to 18:58:59, Monday through Friday
977+
{
978+
name: "Right before the start of the time range",
979+
snapshot: mkSnapshot(
980+
mkPreset(1, "UTC"),
981+
mkSchedule("* 9-18 * * 1-5", 3),
982+
),
983+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 8:58:59 UTC"),
984+
expectedCalculatedInstances: 1,
985+
},
986+
{
987+
name: "Start of the time range",
988+
snapshot: mkSnapshot(
989+
mkPreset(1, "UTC"),
990+
mkSchedule("* 9-18 * * 1-5", 3),
991+
),
992+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 8:59:00 UTC"),
993+
expectedCalculatedInstances: 3,
994+
},
995+
{
996+
name: "9AM - One minute after the start of the time range",
997+
snapshot: mkSnapshot(
998+
mkPreset(1, "UTC"),
999+
mkSchedule("* 9-18 * * 1-5", 3),
1000+
),
1001+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 9:00:00 UTC"),
1002+
expectedCalculatedInstances: 3,
1003+
},
1004+
{
1005+
name: "2PM - The middle of the time range",
1006+
snapshot: mkSnapshot(
1007+
mkPreset(1, "UTC"),
1008+
mkSchedule("* 9-18 * * 1-5", 3),
1009+
),
1010+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 14:00:00 UTC"),
1011+
expectedCalculatedInstances: 3,
1012+
},
1013+
{
1014+
name: "6PM - Around one hour before the end of the time range",
1015+
snapshot: mkSnapshot(
1016+
mkPreset(1, "UTC"),
1017+
mkSchedule("* 9-18 * * 1-5", 3),
1018+
),
1019+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 18:00:00 UTC"),
1020+
expectedCalculatedInstances: 3,
1021+
},
1022+
{
1023+
name: "End of the time range",
1024+
snapshot: mkSnapshot(
1025+
mkPreset(1, "UTC"),
1026+
mkSchedule("* 9-18 * * 1-5", 3),
1027+
),
1028+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 18:58:59 UTC"),
1029+
expectedCalculatedInstances: 3,
1030+
},
1031+
{
1032+
name: "Right after the end of the time range",
1033+
snapshot: mkSnapshot(
1034+
mkPreset(1, "UTC"),
1035+
mkSchedule("* 9-18 * * 1-5", 3),
1036+
),
1037+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 18:59:00 UTC"),
1038+
expectedCalculatedInstances: 1,
1039+
},
1040+
{
1041+
name: "7PM - Around one minute after the end of the time range",
1042+
snapshot: mkSnapshot(
1043+
mkPreset(1, "UTC"),
1044+
mkSchedule("* 9-18 * * 1-5", 3),
1045+
),
1046+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 19:00:00 UTC"),
1047+
expectedCalculatedInstances: 1,
1048+
},
1049+
{
1050+
name: "2AM - Significantly outside the time range",
1051+
snapshot: mkSnapshot(
1052+
mkPreset(1, "UTC"),
1053+
mkSchedule("* 9-18 * * 1-5", 3),
1054+
),
1055+
at: mustParseTime(t, time.RFC1123, "Mon, 02 Jun 2025 02:00:00 UTC"),
1056+
expectedCalculatedInstances: 1,
1057+
},
1058+
{
1059+
name: "Outside the day range #1",
1060+
snapshot: mkSnapshot(
1061+
mkPreset(1, "UTC"),
1062+
mkSchedule("* 9-18 * * 1-5", 3),
1063+
),
1064+
at: mustParseTime(t, time.RFC1123, "Sat, 07 Jun 2025 14:00:00 UTC"),
1065+
expectedCalculatedInstances: 1,
1066+
},
1067+
{
1068+
name: "Outside the day range #2",
1069+
snapshot: mkSnapshot(
1070+
mkPreset(1, "UTC"),
1071+
mkSchedule("* 9-18 * * 1-5", 3),
1072+
),
1073+
at: mustParseTime(t, time.RFC1123, "Sun, 08 Jun 2025 14:00:00 UTC"),
1074+
expectedCalculatedInstances: 1,
1075+
},
1076+
}
1077+
1078+
for _, tc := range testCases {
1079+
tc := tc
1080+
t.Run(tc.name, func(t *testing.T) {
1081+
t.Parallel()
1082+
desiredInstances, err := tc.snapshot.CalculateDesiredInstances(tc.at)
1083+
require.NoError(t, err)
1084+
require.Equal(t, tc.expectedCalculatedInstances, desiredInstances)
1085+
})
1086+
}
1087+
}
1088+
9441089
func mustParseTime(t *testing.T, layout, value string) time.Time {
9451090
t.Helper()
9461091
parsedTime, err := time.Parse(layout, value)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy