Files
HODA/internal/config/config_test.go
T
TMCandClaude Opus 5.5 9d6a921c34
CI / build (push) Successful in 30s
Start HODA: a homelab dashboard built from Docker labels
Apps opt in with sema.dashboard.* labels in their own compose file. The
primary reads its host's containers through a read-only socket proxy,
follows Docker events, and merges in what the agent on the second host
reports. Icons come from the icon label, the dashboard-icons set or the
app's favicon, with a letter as the fallback.

Go with only the standard library, a distroless image, and a Gitea
Actions workflow copied from FiMa's: checks in the Dockerfile's check
stage, a Trivy scan, and a push to git.mariosem.es/msemes/hoda.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:18:20 +01:00

66 lines
2.2 KiB
Go

package config
import (
"strings"
"testing"
"time"
)
func env(vars map[string]string) func(string) string {
return func(key string) string { return vars[key] }
}
func TestDefaults(t *testing.T) {
c, err := parse(env(map[string]string{"NODE_NAME": "host-1"}))
if err != nil {
t.Fatal(err)
}
if c.Mode != ModePrimary || c.Port != "8080" || c.LabelPrefix != "sema.dashboard" || c.Title != "HODA" ||
c.LinkTarget != "_blank" || c.DataDir != "/data" || c.DockerHost != "unix:///var/run/docker.sock" {
t.Errorf("defaults = %+v", c)
}
if c.PeerInterval != 5*time.Second || c.ResyncInterval != time.Minute || c.IconRefresh != 24*time.Hour {
t.Errorf("default intervals = %s, %s, %s", c.PeerInterval, c.ResyncInterval, c.IconRefresh)
}
}
func TestPeers(t *testing.T) {
c, err := parse(env(map[string]string{
"PEERS": " http://10.0.0.12:8081/ , ,https://host-3.lan ",
"PEER_TOKEN": "secret",
"LABEL_PREFIX": "sema.dashboard.",
}))
if err != nil {
t.Fatal(err)
}
if len(c.Peers) != 2 || c.Peers[0] != "http://10.0.0.12:8081" || c.Peers[1] != "https://host-3.lan" {
t.Errorf("peers = %q", c.Peers)
}
if c.LabelPrefix != "sema.dashboard" {
t.Errorf("label prefix = %q, want the trailing dot dropped", c.LabelPrefix)
}
}
func TestInvalid(t *testing.T) {
tests := []struct {
vars map[string]string
want string
}{
{map[string]string{"MODE": "agent"}, "PEER_TOKEN is required"},
{map[string]string{"PEERS": "http://10.0.0.12:8081"}, "PEER_TOKEN is required"},
{map[string]string{"MODE": "agent", "PEER_TOKEN": "x", "PEERS": "http://a"}, "PEERS only applies"},
{map[string]string{"PEERS": "10.0.0.12:8081", "PEER_TOKEN": "x"}, "must start with http"},
{map[string]string{"MODE": "server"}, "must be primary or agent"},
{map[string]string{"PORT": "80a"}, "not a valid port"},
{map[string]string{"PEER_INTERVAL": "5"}, "not a positive duration"},
{map[string]string{"LINK_TARGET": "_top"}, "must be _blank or _self"},
{map[string]string{"LOG_LEVEL": "loud"}, "LOG_LEVEL"},
}
for _, tt := range tests {
_, err := parse(env(tt.vars))
if err == nil || !strings.Contains(err.Error(), tt.want) {
t.Errorf("parse(%v) error = %v, want one containing %q", tt.vars, err, tt.want)
}
}
}