CI / build (push) Successful in 40s
Tiles now show the public URL and, when set, the internal URL as a second link. Label names ignore case and - versus _. Containers HODA can't fully use are listed above the tiles with the reason: labels without enable, a missing url, or an unknown label name with a suggestion (category -> group). To find labels without enable, discovery reads all containers. A "Copy labels" button copies every label as a commented template, and falls back to the copy command where the clipboard API is missing (plain http on the LAN). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
91 lines
3.2 KiB
Go
91 lines
3.2 KiB
Go
package apps
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSnapshotOrder(t *testing.T) {
|
|
s := NewStore()
|
|
s.SetApps(LocalSource, "host-1", []App{
|
|
{ID: "000000000001", Name: "Vaultwarden", Group: "Dev"},
|
|
{ID: "000000000002", Name: "gitea", Group: "Dev"},
|
|
{ID: "000000000003", Name: "Jellyfin", Group: "Media"},
|
|
{ID: "000000000004", Name: "Zebra", Group: "dev", Order: -1},
|
|
{ID: "000000000006", Name: "Adminer", Group: DefaultGroup},
|
|
}, nil)
|
|
s.SetReported("http://host-2:8081", HostStatus{Name: "host-2", OK: true}, []App{
|
|
{ID: "000000000005", Name: "Immich", Group: "Media", Host: "host-2"},
|
|
}, nil)
|
|
|
|
resp := s.Snapshot(nil)
|
|
var names []string
|
|
for _, a := range resp.Apps {
|
|
names = append(names, a.Name)
|
|
}
|
|
want := []string{"Zebra", "gitea", "Vaultwarden", "Immich", "Jellyfin", "Adminer"}
|
|
if len(names) != len(want) {
|
|
t.Fatalf("apps = %v, want %v", names, want)
|
|
}
|
|
for i := range want {
|
|
if names[i] != want[i] {
|
|
t.Fatalf("apps = %v, want %v", names, want)
|
|
}
|
|
}
|
|
if len(resp.Hosts) != 2 || resp.Hosts[0].Name != "host-1" || resp.Hosts[1].Name != "host-2" {
|
|
t.Errorf("hosts = %+v, want host-1 then host-2", resp.Hosts)
|
|
}
|
|
for _, h := range resp.Hosts {
|
|
if !h.OK || h.LastOK != nil {
|
|
t.Errorf("host %+v: a reachable host is sent without lastOk", h)
|
|
}
|
|
}
|
|
if resp.Issues == nil || len(resp.Issues) != 0 {
|
|
t.Errorf("issues = %#v, want an empty list", resp.Issues)
|
|
}
|
|
}
|
|
|
|
func TestSnapshotIssues(t *testing.T) {
|
|
s := NewStore()
|
|
s.SetApps(LocalSource, "host-1", nil, []Issue{{Host: "host-1", Container: "keep", Message: "b"}, {Host: "host-1", Container: "fima", Message: "a"}})
|
|
s.SetReported("http://host-2:8081", HostStatus{Name: "host-2", OK: true}, nil, []Issue{{Host: "host-2", Container: "immich", Message: "c"}})
|
|
resp := s.Snapshot(nil)
|
|
if len(resp.Issues) != 3 || resp.Issues[0].Container != "fima" || resp.Issues[2].Host != "host-2" {
|
|
t.Errorf("issues = %+v, want all three sorted by host, then container", resp.Issues)
|
|
}
|
|
}
|
|
|
|
func TestSetErrorKeepsApps(t *testing.T) {
|
|
s := NewStore()
|
|
at := time.Date(2026, 11, 2, 14, 2, 0, 0, time.UTC)
|
|
s.now = func() time.Time { return at }
|
|
s.SetApps(LocalSource, "host-1", []App{{ID: "000000000001", Name: "Gitea"}}, nil)
|
|
s.SetError(LocalSource, "host-1")
|
|
|
|
resp := s.Snapshot(nil)
|
|
if len(resp.Apps) != 1 {
|
|
t.Fatalf("apps = %d, want the last known app kept", len(resp.Apps))
|
|
}
|
|
if resp.Hosts[0].OK || resp.Hosts[0].LastOK == nil || !resp.Hosts[0].LastOK.Equal(at) {
|
|
t.Errorf("host = %+v, want unreachable, last OK at %s", resp.Hosts[0], at)
|
|
}
|
|
}
|
|
|
|
func TestSnapshotLocalIcons(t *testing.T) {
|
|
s := NewStore()
|
|
s.SetApps(LocalSource, "host-1", []App{{ID: "000000000001", Name: "Gitea"}}, nil)
|
|
s.SetReported("http://host-2:8081", HostStatus{Name: "host-2", OK: true}, []App{
|
|
{ID: "000000000002", Name: "Immich", Icon: "/icons/000000000002?v=abc"},
|
|
}, nil)
|
|
resp := s.Snapshot(func(id string) string { return "/icons/" + id + "?v=local" })
|
|
for _, a := range resp.Apps {
|
|
want := map[string]string{"Gitea": "/icons/000000000001?v=local", "Immich": "/icons/000000000002?v=abc"}[a.Name]
|
|
if a.Icon != want {
|
|
t.Errorf("%s icon = %q, want %q", a.Name, a.Icon, want)
|
|
}
|
|
}
|
|
if key, _, ok := s.Lookup("000000000002"); !ok || key != "http://host-2:8081" {
|
|
t.Errorf("Lookup = %q, %v; want the agent's key", key, ok)
|
|
}
|
|
}
|