package mill import ( "context" "errors" "strings" "testing" "tangled.org/core/spindle/models" "tangled.org/core/spindle/quota" ) var bigWorkflowRefusal = quota.Reservation{ Reason: quota.ReasonRepoLimit, Resource: quota.ResourceWorkflowVCPUs, Scope: quota.ScopeRepo, Requested: 6, Limit: 2, } func placeBigWorkflow(t *testing.T, verdicts ...quota.Reservation) (*quotaCandidate, error) { t.Helper() m, _ := quotaMill(t, &scriptedStore{verdicts: verdicts}) cand := addQuotaCandidate(t, m, "node-a", fixedReport(6, 2048)) wid := models.WorkflowId{PipelineId: models.PipelineId("rkey1"), Name: "build"} slot, err := m.place(context.Background(), "dummy", wid, testWorkflow("build")) if err == nil { slot.Release() } if !errors.Is(err, quota.ErrDenied) { t.Fatalf("place error = %v, want a refusal", err) } // a prefix added to the refusal would show up in front of it in the workflow status if msg := err.Error(); strings.Contains(msg, ": ") || !strings.Contains(msg, "6 vCPUs") || !strings.Contains(msg, "2 vCPUs") { t.Fatalf("place error = %q, want just the refusal with both amounts", msg) } return cand, err } func TestPlaceRefusesWorkflowOverItsLimit(t *testing.T) { cand, _ := placeBigWorkflow(t, bigWorkflowRefusal) if _, released := cand.counts(); released != 1 { t.Errorf("executor seat releases = %d, want 1", released) } } func TestPlaceRefusesWorkflowOverItsLimitBehindAQueue(t *testing.T) { placeBigWorkflow(t, quota.Reservation{Temporary: true, Reason: quota.ReasonRepoLimit}, bigWorkflowRefusal) }