fix(instance): sort public services so the profile order is stable
The cache is a Go map; unsorted output reshuffled on every poll, which made hub-client lists visibly jump around.
This commit is contained in:
@@ -22,6 +22,8 @@ package instance
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.dcntrlized.org/Dcntrlized/Maestro/lib/env"
|
"git.dcntrlized.org/Dcntrlized/Maestro/lib/env"
|
||||||
"git.dcntrlized.org/Dcntrlized/Maestro/lib/federation"
|
"git.dcntrlized.org/Dcntrlized/Maestro/lib/federation"
|
||||||
@@ -103,7 +105,8 @@ func buildIdentity(dataRoot string) InstanceIdentity {
|
|||||||
|
|
||||||
// publicServices filters hidden infrastructure (role-labeled containers such
|
// publicServices filters hidden infrastructure (role-labeled containers such
|
||||||
// as dcntrlized-db / dcntrlized-auth and anything flagged hidden) down to the
|
// as dcntrlized-db / dcntrlized-auth and anything flagged hidden) down to the
|
||||||
// public field set.
|
// public field set. The result is sorted case-insensitively by service name:
|
||||||
|
// the cache is a map, so an unsorted profile would reshuffle on every poll.
|
||||||
func publicServices(all []types.Container) []PublicService {
|
func publicServices(all []types.Container) []PublicService {
|
||||||
public := make([]PublicService, 0, len(all))
|
public := make([]PublicService, 0, len(all))
|
||||||
for _, c := range all {
|
for _, c := range all {
|
||||||
@@ -125,5 +128,8 @@ func publicServices(all []types.Container) []PublicService {
|
|||||||
Image: c.Image,
|
Image: c.Image,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
sort.Slice(public, func(i, j int) bool {
|
||||||
|
return strings.ToLower(public[i].ServiceName) < strings.ToLower(public[j].ServiceName)
|
||||||
|
})
|
||||||
return public
|
return public
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,26 @@ func serve(t *testing.T, dataRoot string, services []types.Container) map[string
|
|||||||
return body
|
return body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPublicServicesSortedCaseInsensitive(t *testing.T) {
|
||||||
|
// The cache is a Go map, so input order is random per call; the profile
|
||||||
|
// must still be stable across polls.
|
||||||
|
all := []types.Container{
|
||||||
|
{ID: "1", ServiceName: "calendar", Status: "running"},
|
||||||
|
{ID: "2", ServiceName: "Blog", Status: "running"},
|
||||||
|
{ID: "3", ServiceName: "auth-proxy", Status: "running"},
|
||||||
|
}
|
||||||
|
got := publicServices(all)
|
||||||
|
want := []string{"auth-proxy", "Blog", "calendar"}
|
||||||
|
if len(got) != len(want) {
|
||||||
|
t.Fatalf("len = %d, want %d", len(got), len(want))
|
||||||
|
}
|
||||||
|
for i := range want {
|
||||||
|
if got[i].ServiceName != want[i] {
|
||||||
|
t.Fatalf("order[%d] = %q, want %q (full: %v)", i, got[i].ServiceName, want[i], got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPublicProfileFiltersHiddenInfra(t *testing.T) {
|
func TestPublicProfileFiltersHiddenInfra(t *testing.T) {
|
||||||
dataRoot := t.TempDir()
|
dataRoot := t.TempDir()
|
||||||
body := serve(t, dataRoot, testServices())
|
body := serve(t, dataRoot, testServices())
|
||||||
|
|||||||
Reference in New Issue
Block a user