137 lines
5.1 KiB
Go
137 lines
5.1 KiB
Go
package accountant
|
|
|
|
import (
|
|
"encoding/json"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"sultan/pkg/ledger"
|
|
)
|
|
|
|
// whereLedger: zwei Payees; kunde.de zieht von webdocker07 nach webdocker11 um,
|
|
// olat.kunde.de verschwindet, andere.de liegt auf dem zweiten Payee.
|
|
func whereLedger(t *testing.T) (*ledger.Ledger, func(time.Time)) {
|
|
t.Helper()
|
|
l, err := ledger.Open(ctx, filepath.Join(t.TempDir(), "accountant.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { l.Close() })
|
|
now := time.Date(2026, 9, 1, 10, 0, 0, 0, time.UTC)
|
|
setNow := func(at time.Time) { now = at }
|
|
l.SetClock(func() time.Time { return now })
|
|
for _, id := range []string{"webproxy11", "webproxy12"} {
|
|
l.AddInvite(ctx, "tok-"+id, id, now.Add(time.Hour))
|
|
if _, err := l.Enroll(ctx, "tok-"+id, ledger.Payee{Hostname: id + ".lan", PublicKey: "key-" + id}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return l, setNow
|
|
}
|
|
|
|
func save(t *testing.T, l *ledger.Ledger, payeeID string, rep Report) {
|
|
t.Helper()
|
|
if err := StoreReport(ctx, l, payeeID, rep); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func whereReport(node string, routes ...ReportRoute) Report {
|
|
return Report{
|
|
GeneratedAt: time.Now(),
|
|
Tenants: []ReportTenant{{ID: "kunde", Name: "Kunde A"}, {ID: "andere", Name: "Andere GmbH"}},
|
|
Nodes: []ReportNode{{ID: node, Tenant: "kunde", FQDN: node + ".lan.r25dc.de", Connected: true, OS: "Debian 13",
|
|
DockerVersion: "29.8.2", NetBirdIP: "100.92.10.4"}},
|
|
Routes: routes,
|
|
}
|
|
}
|
|
|
|
func route(tenant, node, router string, hosts ...string) ReportRoute {
|
|
return ReportRoute{Tenant: tenant, Node: node, Router: router, Protocol: "http", Hosts: hosts, Workload: "kunde-a-" + router + "-1",
|
|
Backend: "http://10.0.0.11:8081", BackendFQDN: node + ".lan.r25dc.de:8081", Active: true,
|
|
ComposeDir: "/srv/kunde-a", ComposeProject: "kunde-a", State: "running", Health: "healthy"}
|
|
}
|
|
|
|
func TestWhere(t *testing.T) {
|
|
l, setNow := whereLedger(t)
|
|
t1 := time.Date(2026, 9, 1, 10, 0, 0, 0, time.UTC)
|
|
save(t, l, "webproxy11", whereReport("webdocker07", route("kunde", "webdocker07", "wp", "kunde.de"),
|
|
route("kunde", "webdocker07", "olat", "olat.kunde.de")))
|
|
andere := whereReport("n9", route("andere", "n9", "web", "andere.de"))
|
|
save(t, l, "webproxy12", andere)
|
|
|
|
t2 := t1.Add(30 * 24 * time.Hour)
|
|
setNow(t2)
|
|
save(t, l, "webproxy11", whereReport("webdocker11", route("kunde", "webdocker11", "wp", "kunde.de", "www.kunde.de")))
|
|
|
|
res, err := Where(ctx, l, "kunde.de")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(res.Current) != 1 {
|
|
t.Fatalf("aktuell: %+v", res.Current)
|
|
}
|
|
h := res.Current[0]
|
|
if h.Payee != "webproxy11" || h.Route.Router != "wp" || h.TenantName != "Kunde A" || h.Node.FQDN != "webdocker11.lan.r25dc.de" ||
|
|
h.Route.ComposeDir != "/srv/kunde-a" || !h.Since.Equal(t2) || !h.ReportAt.Equal(t2) {
|
|
t.Errorf("Treffer: %+v", h)
|
|
}
|
|
if len(h.Previous) != 1 || h.Previous[0].Node != "webdocker07" || !h.Previous[0].Ended.Equal(t2) || !h.Previous[0].FirstSeen.Equal(t1) {
|
|
t.Errorf("vorher: %+v", h.Previous)
|
|
}
|
|
// olat.kunde.de passt (Teiltreffer "kunde.de"), ist aber verschwunden.
|
|
if len(res.Gone) != 1 || res.Gone[0].Router != "olat" || !res.Gone[0].Ended.Equal(t2) {
|
|
t.Errorf("verschwunden: %+v", res.Gone)
|
|
}
|
|
|
|
// Teiltreffer und Mandant.
|
|
if r, _ := Where(ctx, l, "WWW.Kunde"); len(r.Current) != 1 {
|
|
t.Errorf("Teiltreffer: %+v", r)
|
|
}
|
|
if r, _ := Where(ctx, l, "andere"); len(r.Current) != 1 || r.Current[0].Payee != "webproxy12" {
|
|
t.Errorf("Mandant: %+v", r)
|
|
}
|
|
if r, _ := Where(ctx, l, "gibts-nicht.de"); len(r.Current)+len(r.Gone) != 0 {
|
|
t.Errorf("kein Treffer erwartet: %+v", r)
|
|
}
|
|
if r, _ := Where(ctx, l, "_"); len(r.Current)+len(r.Gone) != 0 {
|
|
t.Errorf("Platzhalter wirkt als Joker: %+v", r)
|
|
}
|
|
}
|
|
|
|
// Der Bericht geht über den Endpunkt in die Historie ein.
|
|
func TestReport_RecordsHistory(t *testing.T) {
|
|
a := start(t, "")
|
|
key := enrolledPayee(t, a, "webproxy11")
|
|
body, _ := json.Marshal(whereReport("webdocker11", route("kunde", "webdocker11", "wp", "kunde.de")))
|
|
postReport(t, a, key, body)
|
|
l, _ := ledger.Open(ctx, filepath.Join(a.DataDir(), "accountant.db"))
|
|
defer l.Close()
|
|
spans, err := l.RouteHistory(ctx, ledger.HistoryFilter{})
|
|
if err != nil || len(spans) != 1 || spans[0].Payee != "webproxy11" || spans[0].BackendFQDN != "webdocker11.lan.r25dc.de:8081" {
|
|
t.Errorf("Historie: %+v, %v", spans, err)
|
|
}
|
|
}
|
|
|
|
func TestRoutes(t *testing.T) {
|
|
l, _ := whereLedger(t)
|
|
save(t, l, "webproxy11", whereReport("webdocker11", route("kunde", "webdocker11", "wp", "kunde.de"),
|
|
route("kunde", "webdocker11", "olat", "olat.kunde.de")))
|
|
save(t, l, "webproxy12", whereReport("n9", route("andere", "n9", "web", "andere.de")))
|
|
|
|
all, err := Routes(ctx, l, RoutesFilter{})
|
|
if err != nil || len(all) != 3 {
|
|
t.Fatalf("Routes = %+v, %v", all, err)
|
|
}
|
|
if all[0].Route.Hosts[0] != "andere.de" || all[2].Route.Hosts[0] != "olat.kunde.de" {
|
|
t.Errorf("nicht nach Host sortiert: %v %v %v", all[0].Route.Hosts, all[1].Route.Hosts, all[2].Route.Hosts)
|
|
}
|
|
if r, _ := Routes(ctx, l, RoutesFilter{Tenant: "kunde"}); len(r) != 2 {
|
|
t.Errorf("--tenant: %+v", r)
|
|
}
|
|
if r, _ := Routes(ctx, l, RoutesFilter{Payee: "webproxy12"}); len(r) != 1 || r[0].Since.IsZero() {
|
|
t.Errorf("--payee: %+v", r)
|
|
}
|
|
}
|