Files
vibeproxy/internal/web/templates_render_test.go
T
owenandClaude Sonnet 5 ba1f7c4c03 Initial vibeproxy implementation
Self-contained HTTP/HTTPS/TCP/UDP reverse proxy manager written in Go,
with SQLite storage, a Bootstrap 5 admin UI (Go templates, no JS
framework), and a REST API under /api/v1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QTXFrNP1imCW7jtfL5SZrw
2026-08-17 10:28:59 -05:00

86 lines
4.5 KiB
Go

package web
import (
"bytes"
"testing"
"time"
"github.com/owen/vibeproxy/internal/database"
"github.com/owen/vibeproxy/internal/models"
"github.com/owen/vibeproxy/internal/stats"
)
func mustRender(t *testing.T, name string, data PageData) {
t.Helper()
var buf bytes.Buffer
if err := templates.ExecuteTemplate(&buf, name, data); err != nil {
t.Fatalf("render %s: %v", name, err)
}
if buf.Len() == 0 {
t.Fatalf("render %s: empty output", name)
}
}
func TestRenderAllPages(t *testing.T) {
now := time.Now()
aid := int64(1)
host := models.ProxyHost{
ID: 1, Name: "example", Type: models.ProxyHostTypeProxy, Domains: []string{"example.com"},
ForwardScheme: "http", LoadBalancingMethod: "round_robin", CertificateID: &aid, AccessListID: &aid,
Backends: []models.Backend{{ID: 1, Host: "10.0.0.1", Port: 8080, Weight: 1, Enabled: true, HealthCheckType: models.HealthCheckTCP}},
CustomHeaders: []models.CustomHeader{{Direction: models.HeaderDirectionRequest, Action: models.HeaderActionSet, Name: "X-Test", Value: "1"}},
Enabled: true, CreatedAt: now, UpdatedAt: now,
}
redirectHost := host
redirectHost.Type = models.ProxyHostTypeRedirect
redirectHost.RedirectTargetURL = "https://new.example.com"
redirectHost.RedirectCode = 301
acl := models.AccessList{ID: 1, Name: "Internal", DefaultAllow: false,
Rules: []models.AccessRule{{Action: models.AccessAllow, CIDR: "10.0.0.0/8"}},
BasicAuthUsers: []models.AccessListUser{{Username: "bob", PasswordHash: "hash"}},
}
cert := models.Certificate{ID: 1, Name: "example", Type: models.CertTypeLetsEncrypt, Domains: []string{"example.com"}, NotAfter: &now}
stream := models.Stream{ID: 1, Protocol: models.StreamTCP, ListenIP: "0.0.0.0", ListenPort: 25565, DestinationHost: "10.0.0.1", DestinationPort: 25565, Enabled: true}
reqLog := models.RequestLog{ID: 1, Timestamp: now, ProxyHostName: "example", ClientIP: "1.2.3.4", Method: "GET", Host: "example.com", Path: "/", Status: 200, ResponseSize: 100, Backend: "10.0.0.1:8080", ResponseTimeMS: 12}
auditLog := models.AuditLog{ID: 1, Timestamp: now, Actor: "admin", Action: "proxy_created", Target: "example", Details: "domains=[example.com]"}
token := models.APIToken{ID: 1, Name: "ci", Prefix: "vp_abcd12", CreatedAt: now}
tests := []struct {
name string
pd PageData
}{
{"dashboard", PageData{Data: &stats.Dashboard{
BackendHealth: []stats.BackendHealthEntry{{ProxyHost: "example", Backend: "10.0.0.1", Healthy: true}},
StatusBreakdown: []database.StatusCount{{Status: 200, Count: 5}},
TopHosts: []database.HostCount{{Host: "example.com", Count: 5}},
TopClients: []database.HostCount{{Host: "1.2.3.4", Count: 5}},
CertsExpiringSoon: []models.Certificate{cert},
RecentErrors: []models.RequestLog{reqLog},
}}},
{"proxy_hosts", PageData{CSRFToken: "tok", Data: map[string]any{
"Hosts": []models.ProxyHost{host, redirectHost}, "AccessLists": []models.AccessList{acl}, "Certificates": []models.Certificate{cert},
}}},
{"proxy_host_form", PageData{CSRFToken: "tok", Data: proxyHostFormData{Host: host, AccessLists: []models.AccessList{acl}, Certificates: []models.Certificate{cert}, IsNew: false}}},
{"proxy_host_form", PageData{CSRFToken: "tok", Data: proxyHostFormData{Host: redirectHost, AccessLists: []models.AccessList{acl}, Certificates: []models.Certificate{cert}, IsNew: true}}},
{"streams", PageData{CSRFToken: "tok", Data: []models.Stream{stream}}},
{"stream_form", PageData{CSRFToken: "tok", Data: map[string]any{"Stream": stream, "IsNew": false}}},
{"backends", PageData{Data: []backendRow{{ProxyHostID: 1, ProxyHostName: "example", Host: "10.0.0.1", Port: 8080, Weight: 1, Enabled: true, Healthy: true, HealthCheck: "tcp"}}}},
{"certificates", PageData{CSRFToken: "tok", Data: []models.Certificate{cert}}},
{"access_lists", PageData{CSRFToken: "tok", Data: []models.AccessList{acl}}},
{"access_list_form", PageData{CSRFToken: "tok", Data: map[string]any{"List": acl, "IsNew": false}}},
{"logs", PageData{Data: map[string]any{"Logs": []models.RequestLog{reqLog}, "Total": 1, "Page": 1, "TotalPages": 1, "Query": "", "Status": 0}}},
{"logs_audit", PageData{Data: map[string]any{"Logs": []models.AuditLog{auditLog}, "Total": 1, "Page": 1, "TotalPages": 1}}},
{"settings", PageData{CSRFToken: "tok", Data: models.Settings{AdminUsername: "admin", TrustedProxyCIDRs: []string{"10.0.0.0/8"}}}},
{"api_tokens", PageData{CSRFToken: "tok", Data: []models.APIToken{token}}},
}
for _, tc := range tests {
mustRender(t, tc.name, tc.pd)
}
}