Skip to content

Commit 8bc6abc

Browse files
authored
scheduler: basic cluster reconciler safety properties for service jobs (#26167)
1 parent 009927d commit 8bc6abc

File tree

1 file changed

+55
-9
lines changed

1 file changed

+55
-9
lines changed

scheduler/reconciler/reconcile_cluster_prop_test.go

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ func TestAllocReconciler_PropTest(t *testing.T) {
2525
t.Run("batch jobs", rapid.MakeCheck(func(t *rapid.T) {
2626
ar := genAllocReconciler(structs.JobTypeBatch, &idGenerator{}).Draw(t, "reconciler")
2727
results := ar.Compute()
28+
2829
if results == nil {
2930
t.Fatal("results should never be nil")
3031
}
@@ -34,10 +35,48 @@ func TestAllocReconciler_PropTest(t *testing.T) {
3435
t.Run("service jobs", rapid.MakeCheck(func(t *rapid.T) {
3536
ar := genAllocReconciler(structs.JobTypeService, &idGenerator{}).Draw(t, "reconciler")
3637
results := ar.Compute()
38+
39+
/*
40+
SAFETY properties ("something bad never happens")
41+
*/
42+
3743
if results == nil {
3844
t.Fatal("results should never be nil")
3945
}
40-
// TODO(tgross): this where the properties under test go
46+
47+
// stopped jobs
48+
if ar.jobState.Job.Stopped() {
49+
if ar.jobState.DeploymentCurrent != nil {
50+
if results.Deployment != nil {
51+
t.Fatal("stopped jobs with current deployments should never result in a new deployment")
52+
}
53+
if results.Stop == nil {
54+
t.Fatal("stopped jobs with current deployments should always have stopped allocs")
55+
}
56+
}
57+
}
58+
59+
if results.DesiredTGUpdates == nil {
60+
t.Fatal("we should never have nil desired task group updates")
61+
}
62+
63+
if ar.jobState.DeploymentFailed && results.Deployment != nil {
64+
t.Fatal("failed deployments should never result in new deployments")
65+
}
66+
67+
if !ar.clusterState.SupportsDisconnectedClients && results.ReconnectUpdates != nil {
68+
t.Fatal("task groups that don't support disconnected clients should never result in reconnect updates")
69+
}
70+
71+
if ar.jobState.DeploymentCurrent == nil && ar.jobState.DeploymentOld == nil && len(ar.jobState.ExistingAllocs) == 0 {
72+
count := 0
73+
for _, tg := range ar.jobState.Job.TaskGroups {
74+
count += tg.Count
75+
}
76+
if len(results.Place) > count {
77+
t.Fatal("for new jobs, amount of allocs to place should never exceed total tg count")
78+
}
79+
}
4180
}))
4281
}
4382

@@ -125,7 +164,7 @@ func genDeployment(idg *idGenerator, job *structs.Job, allocs []*structs.Allocat
125164
AutoPromote: tg.Update.AutoPromote,
126165
ProgressDeadline: tg.Update.ProgressDeadline,
127166
RequireProgressBy: time.Time{},
128-
Promoted: false, // TODO(tgross): what to do with this?
167+
Promoted: rapid.Bool().Draw(t, "promoted"),
129168
PlacedCanaries: []string{},
130169
DesiredCanaries: tg.Update.Canary,
131170
DesiredTotal: tg.Count,
@@ -163,13 +202,20 @@ func genDeployment(idg *idGenerator, job *structs.Job, allocs []*structs.Allocat
163202
JobCreateIndex: job.CreateIndex,
164203
IsMultiregion: false,
165204
TaskGroups: dstates,
166-
Status: structs.DeploymentStatusRunning, // TODO(tgross)
167-
StatusDescription: "",
168-
EvalPriority: 0,
169-
CreateIndex: job.CreateIndex,
170-
ModifyIndex: 0,
171-
CreateTime: 0,
172-
ModifyTime: 0,
205+
Status: rapid.SampledFrom([]string{
206+
structs.DeploymentStatusRunning,
207+
structs.DeploymentStatusPending,
208+
structs.DeploymentStatusInitializing,
209+
structs.DeploymentStatusPaused,
210+
structs.DeploymentStatusFailed,
211+
structs.DeploymentStatusSuccessful,
212+
}).Draw(t, "deployment_status"),
213+
StatusDescription: "",
214+
EvalPriority: 0,
215+
CreateIndex: job.CreateIndex,
216+
ModifyIndex: 0,
217+
CreateTime: 0,
218+
ModifyTime: 0,
173219
}
174220
})
175221
}

0 commit comments

Comments
 (0)