package web import ( "bytes" "html/template" "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/config" "gitea.dooplex.hu/admin/felhom-controller/internal/stacks" ) // TestRouteUnpublished asserts F5: routeUnpublished is true exactly for the states where Traefik // withholds the public route (unhealthy / restarting) and false otherwise. func TestRouteUnpublished(t *testing.T) { cases := []struct { state stacks.ContainerState want bool }{ {stacks.StateUnhealthy, true}, {stacks.StateRestarting, true}, {stacks.StateRunning, false}, {stacks.StateStarting, false}, {stacks.StateDeploying, false}, {stacks.StateStopped, false}, {stacks.StateExited, false}, {stacks.StateNotDeployed, false}, {stacks.StatePaused, false}, } for _, c := range cases { if got := routeUnpublished(c.state); got != c.want { t.Errorf("routeUnpublished(%q) = %v, want %v", c.state, got, c.want) } } } // TestTemplatesParseWithFuncmap asserts the real embedded templates (including the stacks.html / // dashboard.html edits that reference routeUnpublished) parse with the production funcmap. Catches an // unregistered func or a template syntax error introduced by the F5 edits. func TestTemplatesParseWithFuncmap(t *testing.T) { s := &Server{cfg: &config.Config{}} if _, err := template.New("").Funcs(s.templateFuncMap()).ParseFS(templateFS, "templates/*.html"); err != nil { t.Fatalf("templates failed to parse with funcmap: %v", err) } } // TestRouteUnpublishedIndicatorRenders asserts the dashboard/stacks card guard renders the distinct // indicator for a DEPLOYED + unhealthy stack, and NOT for a healthy one — the exact condition both // edited templates use ({{if and .Deployed (routeUnpublished .State)}}). func TestRouteUnpublishedIndicatorRenders(t *testing.T) { s := &Server{cfg: &config.Config{}} const frag = `{{if and .Deployed (routeUnpublished .State)}}URL-NOT-PUBLISHED{{end}}` tmpl, err := template.New("frag").Funcs(s.templateFuncMap()).Parse(frag) if err != nil { t.Fatal(err) } type row struct { Deployed bool State stacks.ContainerState } render := func(r row) string { var b bytes.Buffer if err := tmpl.Execute(&b, r); err != nil { t.Fatal(err) } return b.String() } if got := render(row{Deployed: true, State: stacks.StateUnhealthy}); !strings.Contains(got, "URL-NOT-PUBLISHED") { t.Errorf("deployed+unhealthy should show the indicator, got %q", got) } if got := render(row{Deployed: true, State: stacks.StateRunning}); strings.Contains(got, "URL-NOT-PUBLISHED") { t.Errorf("deployed+running must NOT show the indicator, got %q", got) } if got := render(row{Deployed: false, State: stacks.StateUnhealthy}); strings.Contains(got, "URL-NOT-PUBLISHED") { t.Errorf("not-deployed must NOT show the indicator, got %q", got) } }