test(worker): script the kernel out of the port bookkeeping specs

Probing every candidate before handing it out is right, and it made sixteen
specs that were never about the kernel depend on it. They build a supervisor
directly, name the ports they expect literally, and those literals sit inside
Linux's default ephemeral range, so with the real probe each one asks this host
whether 50051 is bindable at that instant.

The first full -race run over ./core/... and ./pkg/... after the probe landed
went red on four of them, and holding 50051, 50052, 50060 and 50061 from
another process turns eleven red deterministically. Nothing was wrong with the
allocator in either case: something else on the machine held a port, which is
the situation the probe exists to survive.

So the specs that assert bookkeeping now inject a probe that always says yes,
and say why once. The two specs that are about the probe leave the field unset
and keep asking real sockets, which is what still fails if the probe is removed.

Assisted-by: Claude Opus 5 [claude-code]
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto committed 2026-09-06 07:01:23 +00:00
1 parent 7b66df6651
commit d170de2095
2 files changed
+34 -2

No files matched your search

@@ -16,6 +16,22 @@ func mustAllocate(s *backendSupervisor, key string) int {
return port
}
// bookkeepingProbe is the port probe every supervisor in this file and in
// port_quarantine_test.go runs with, and it always says yes.
//
// Those specs are about the allocator's own bookkeeping, and each names the
// ports it expects literally. Those literals sit inside Linux's default
// ephemeral range (32768-60999), so with the real probe every one of them asks
// this host whether 50051 happens to be bindable at that instant. Anything
// holding one turns the spec red: another suite in the same run, or any other
// process on the machine. Eleven of them failed together the first time
// something else on the box held 50051, 50052, 50060 and 50061.
//
// Scripting the kernel out is what keeps these specs about the bookkeeping. The
// probe itself is covered against real sockets in port_bindable_test.go, which
// leaves this field unset on purpose.
func bookkeepingProbe(int) bool { return true }
var _ = Describe("Backend gRPC port allocator", func() {
Describe("range exhaustion", func() {
It("reports an explicit error instead of handing out an unbindable port", func() {
@@ -25,6 +41,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
// at the allocator. Exhaustion must be named as exhaustion.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50052,
@@ -47,6 +64,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
It("does not hand out a port beyond the end of the range", func() {
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50053,
@@ -71,6 +89,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
bp := &backendProcess{port: 50051}
s := &backendSupervisor{
processes: map[string]*backendProcess{"model#0": bp},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50052,
maxPort: 50060,
@@ -91,6 +110,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
// the range. Before the fix this consumed a fresh port per restart.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50053,
@@ -140,6 +160,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
// by construction rather than by racing a quarantine timer.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50060,
@@ -161,6 +182,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
It("reuses an unowned port before growing the range", func() {
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50060,
@@ -181,6 +203,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
// vanishingly rare misroute for a guaranteed outage.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50051,
@@ -207,6 +230,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
// problem.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50060,
@@ -228,6 +252,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
// zero would hand a just-released port straight to another model.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50060,
@@ -248,6 +273,7 @@ var _ = Describe("Backend gRPC port allocator", func() {
// range has ports, however many distinct keys the worker sees.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
minPort: 50051,
nextPort: 50051,
maxPort: 50052,
+8 -2
View File
@@ -28,6 +28,7 @@ var _ = Describe("Backend port quarantine", func() {
bp := &backendProcess{port: 50051}
s := &backendSupervisor{
processes: map[string]*backendProcess{"model#0": bp},
portIsFree: bookkeepingProbe,
nextPort: 50060,
portQuarantine: time.Hour,
}
@@ -49,6 +50,7 @@ var _ = Describe("Backend port quarantine", func() {
bp := &backendProcess{port: 50051}
s := &backendSupervisor{
processes: map[string]*backendProcess{"model#0": bp},
portIsFree: bookkeepingProbe,
nextPort: 50060,
portQuarantine: time.Millisecond,
}
@@ -68,6 +70,7 @@ var _ = Describe("Backend port quarantine", func() {
bp := &backendProcess{port: 50051}
s := &backendSupervisor{
processes: map[string]*backendProcess{"model#0": bp},
portIsFree: bookkeepingProbe,
nextPort: 50060,
portQuarantine: time.Hour,
}
@@ -83,6 +86,7 @@ var _ = Describe("Backend port quarantine", func() {
It("prefers a released port over growing the range", func() {
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
nextPort: 50060,
portQuarantine: time.Millisecond,
}
@@ -98,6 +102,7 @@ var _ = Describe("Backend port quarantine", func() {
It("does not sweep a port whose quarantine is still running", func() {
s := &backendSupervisor{
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
nextPort: 50060,
portQuarantine: time.Hour,
}
@@ -113,8 +118,9 @@ var _ = Describe("Backend port quarantine", func() {
// The zero value must not degrade to "no quarantine": every
// supervisor built outside the tests leaves the field unset.
s := &backendSupervisor{
processes: map[string]*backendProcess{},
nextPort: 50060,
processes: map[string]*backendProcess{},
portIsFree: bookkeepingProbe,
nextPort: 50060,
}
s.releasePort(50051)