Skip to content

Commit 162fd18

Browse files
test: add integration test
1 parent 63ffcc7 commit 162fd18

File tree

4 files changed

+113
-11
lines changed

4 files changed

+113
-11
lines changed

coderd/prebuilds/global_snapshot.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package prebuilds
22

33
import (
4+
"github.com/coder/quartz"
45
"time"
56

67
"github.com/google/uuid"
@@ -18,6 +19,7 @@ type GlobalSnapshot struct {
1819
PrebuildsInProgress []database.CountInProgressPrebuildsRow
1920
Backoffs []database.GetPresetsBackoffRow
2021
HardLimitedPresetsMap map[uuid.UUID]database.GetPresetsAtFailureLimitRow
22+
clock quartz.Clock
2123
}
2224

2325
func NewGlobalSnapshot(
@@ -27,6 +29,7 @@ func NewGlobalSnapshot(
2729
prebuildsInProgress []database.CountInProgressPrebuildsRow,
2830
backoffs []database.GetPresetsBackoffRow,
2931
hardLimitedPresets []database.GetPresetsAtFailureLimitRow,
32+
clock quartz.Clock,
3033
) GlobalSnapshot {
3134
hardLimitedPresetsMap := make(map[uuid.UUID]database.GetPresetsAtFailureLimitRow, len(hardLimitedPresets))
3235
for _, preset := range hardLimitedPresets {
@@ -40,6 +43,7 @@ func NewGlobalSnapshot(
4043
PrebuildsInProgress: prebuildsInProgress,
4144
Backoffs: backoffs,
4245
HardLimitedPresetsMap: hardLimitedPresetsMap,
46+
clock: clock,
4347
}
4448
}
4549

@@ -88,6 +92,7 @@ func (s GlobalSnapshot) FilterByPreset(presetID uuid.UUID) (*PresetSnapshot, err
8892
InProgress: inProgress,
8993
Backoff: backoffPtr,
9094
IsHardLimited: isHardLimited,
95+
clock: s.clock,
9196
}, nil
9297
}
9398

coderd/prebuilds/preset_snapshot.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type PresetSnapshot struct {
4646
InProgress []database.CountInProgressPrebuildsRow
4747
Backoff *database.GetPresetsBackoffRow
4848
IsHardLimited bool
49+
clock quartz.Clock
4950
}
5051

5152
// ReconciliationState represents the processed state of a preset's prebuilds,
@@ -155,9 +156,10 @@ func (p PresetSnapshot) CalculateState() *ReconciliationState {
155156

156157
if p.isActive() {
157158
var err error
158-
desired, err = p.CalculateDesiredInstances(time.Now())
159+
desired, err = p.CalculateDesiredInstances(p.clock.Now())
159160
if err != nil {
160161
// TODO: handle error
162+
panic(err)
161163
}
162164
eligible = p.countEligible()
163165
extraneous = max(actual-expired-desired, 0)

coderd/prebuilds/preset_snapshot_test.go

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func TestNoPrebuilds(t *testing.T) {
8484
preset(true, 0, current),
8585
}
8686

87-
snapshot := prebuilds.NewGlobalSnapshot(presets, nil, nil, nil, nil, nil)
87+
snapshot := prebuilds.NewGlobalSnapshot(presets, nil, nil, nil, nil, nil, quartz.NewMock(t))
8888
ps, err := snapshot.FilterByPreset(current.presetID)
8989
require.NoError(t, err)
9090

@@ -106,7 +106,7 @@ func TestNetNew(t *testing.T) {
106106
preset(true, 1, current),
107107
}
108108

109-
snapshot := prebuilds.NewGlobalSnapshot(presets, nil, nil, nil, nil, nil)
109+
snapshot := prebuilds.NewGlobalSnapshot(presets, nil, nil, nil, nil, nil, quartz.NewMock(t))
110110
ps, err := snapshot.FilterByPreset(current.presetID)
111111
require.NoError(t, err)
112112

@@ -148,7 +148,7 @@ func TestOutdatedPrebuilds(t *testing.T) {
148148
var inProgress []database.CountInProgressPrebuildsRow
149149

150150
// 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))
152152
ps, err := snapshot.FilterByPreset(outdated.presetID)
153153
require.NoError(t, err)
154154

@@ -214,7 +214,7 @@ func TestDeleteOutdatedPrebuilds(t *testing.T) {
214214
}
215215

216216
// 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))
218218
ps, err := snapshot.FilterByPreset(outdated.presetID)
219219
require.NoError(t, err)
220220

@@ -459,7 +459,7 @@ func TestInProgressActions(t *testing.T) {
459459
}
460460

461461
// 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))
463463
ps, err := snapshot.FilterByPreset(current.presetID)
464464
require.NoError(t, err)
465465

@@ -502,7 +502,7 @@ func TestExtraneous(t *testing.T) {
502502
var inProgress []database.CountInProgressPrebuildsRow
503503

504504
// 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))
506506
ps, err := snapshot.FilterByPreset(current.presetID)
507507
require.NoError(t, err)
508508

@@ -683,7 +683,7 @@ func TestExpiredPrebuilds(t *testing.T) {
683683
}
684684

685685
// 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))
687687
ps, err := snapshot.FilterByPreset(current.presetID)
688688
require.NoError(t, err)
689689

@@ -719,7 +719,7 @@ func TestDeprecated(t *testing.T) {
719719
var inProgress []database.CountInProgressPrebuildsRow
720720

721721
// 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))
723723
ps, err := snapshot.FilterByPreset(current.presetID)
724724
require.NoError(t, err)
725725

@@ -772,7 +772,7 @@ func TestLatestBuildFailed(t *testing.T) {
772772
}
773773

774774
// 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))
776776
psCurrent, err := snapshot.FilterByPreset(current.presetID)
777777
require.NoError(t, err)
778778

@@ -865,7 +865,7 @@ func TestMultiplePresetsPerTemplateVersion(t *testing.T) {
865865
},
866866
}
867867

868-
snapshot := prebuilds.NewGlobalSnapshot(presets, nil, nil, inProgress, nil, nil)
868+
snapshot := prebuilds.NewGlobalSnapshot(presets, nil, nil, inProgress, nil, nil, quartz.NewMock(t))
869869

870870
// Nothing has to be created for preset 1.
871871
{
@@ -905,6 +905,91 @@ func TestMultiplePresetsPerTemplateVersion(t *testing.T) {
905905
}
906906
}
907907

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+
908993
func TestMatchesCron(t *testing.T) {
909994
t.Parallel()
910995
testCases := []struct {
@@ -1294,6 +1379,15 @@ func preset(active bool, instances int32, opts options, muts ...func(row databas
12941379
return entry
12951380
}
12961381

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+
12971391
func prebuiltWorkspace(
12981392
opts options,
12991393
clock quartz.Clock,

enterprise/coderd/prebuilds/reconcile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ func (c *StoreReconciler) SnapshotState(ctx context.Context, store database.Stor
392392
allPrebuildsInProgress,
393393
presetsBackoff,
394394
hardLimitedPresets,
395+
c.clock,
395396
)
396397
return nil
397398
}, &database.TxOptions{

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