erste module drin.

zwischenstand: Architektur aktualisiert, TOFU implementiert,
This commit is contained in:
br committed 2026-10-01 22:22:13 +02:00
1 parent 9d5789c5d7
commit c8df9d7651
41 files changed
+6455 -36

No files matched your search

+146
View File
@@ -0,0 +1,146 @@
package traefik
import (
"encoding/json"
"testing"
"gopkg.in/yaml.v3"
)
func mustJSON(t *testing.T, v any) string {
t.Helper()
b, err := json.Marshal(v)
if err != nil {
t.Fatalf("json.Marshal: %v", err)
}
return string(b)
}
func sampleConfig() *Configuration {
return &Configuration{HTTP: &HTTPConfiguration{
Routers: map[string]*Router{
"r": {EntryPoints: []string{"web"}, Service: "s", Rule: "Host(`a.de`)", TLS: &RouterTLS{}},
},
Services: map[string]*Service{
"s": {LoadBalancer: &ServersLoadBalancer{Servers: []Server{{URL: "http://10.0.0.1:80"}}}},
},
}}
}
func TestMarshal_JSON(t *testing.T) {
got, err := sampleConfig().Marshal(FormatJSON)
if err != nil {
t.Fatalf("unerwarteter Fehler: %v", err)
}
want := `{"http":{"routers":{"r":{"entryPoints":["web"],"service":"s","rule":"Host(` + "`a.de`" + `)","tls":{}}},` +
`"services":{"s":{"loadBalancer":{"servers":[{"url":"http://10.0.0.1:80"}]}}}}}`
if string(got) != want {
t.Errorf("JSON weicht ab\n got: %s\nwant: %s", got, want)
}
}
func TestMarshal_YAML(t *testing.T) {
got, err := sampleConfig().Marshal(FormatYAML)
if err != nil {
t.Fatalf("unerwarteter Fehler: %v", err)
}
want := "http:\n" +
" routers:\n" +
" r:\n" +
" entryPoints:\n" +
" - web\n" +
" service: s\n" +
" rule: Host(`a.de`)\n" +
" tls: {}\n" +
" services:\n" +
" s:\n" +
" loadBalancer:\n" +
" servers:\n" +
" - url: http://10.0.0.1:80\n"
if string(got) != want {
t.Errorf("YAML weicht ab\n got:\n%s\nwant:\n%s", got, want)
}
}
func TestMarshal_Empty(t *testing.T) {
for _, c := range []*Configuration{nil, {}} {
j, err := c.Marshal(FormatJSON)
if err != nil || string(j) != "{}" {
t.Errorf("JSON = %q, %v; erwartet {}", j, err)
}
y, err := c.Marshal(FormatYAML)
if err != nil || string(y) != "{}\n" {
t.Errorf("YAML = %q, %v; erwartet {}\\n", y, err)
}
}
}
func TestMarshal_UnknownFormat(t *testing.T) {
if _, err := sampleConfig().Marshal("toml"); err == nil {
t.Error("erwartet Fehler für unbekanntes Format")
}
}
// Die Ausgabe muss sich verlustfrei zurücklesen lassen – inklusive der
// verschachtelten Middleware-Maps und der optionalen Felder.
func TestMarshal_RoundTrip(t *testing.T) {
orig, err := FromLabels("100.64.0.42", wordpressLabels())
if err != nil {
t.Fatalf("FromLabels: %v", err)
}
orig.HTTP.Services["wp"].LoadBalancer.PassHostHeader = boolPtr(false)
orig.HTTP.Routers["wp"].Priority = 7
decoders := map[Format]func([]byte, any) error{
FormatJSON: json.Unmarshal,
FormatYAML: yaml.Unmarshal,
}
for f, decode := range decoders {
t.Run(string(f), func(t *testing.T) {
b, err := orig.Marshal(f)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
var back Configuration
if err := decode(b, &back); err != nil {
t.Fatalf("Unmarshal: %v\n%s", err, b)
}
// Vergleich über JSON statt reflect.DeepEqual: yaml.v3 dekodiert
// verschachtelte Maps in den Typ der äußeren Map (Middleware statt
// map[string]any), inhaltlich ist das identisch.
if got, want := mustJSON(t, &back), mustJSON(t, orig); got != want {
t.Errorf("Round-Trip weicht ab\n got: %s\nwant: %s", got, want)
}
})
}
}
func TestParseFormat(t *testing.T) {
tests := []struct {
in string
want Format
wantErr bool
}{
{"", FormatJSON, false},
{"json", FormatJSON, false},
{" JSON ", FormatJSON, false},
{"yaml", FormatYAML, false},
{"YML", FormatYAML, false},
{"toml", "", true},
}
for _, tt := range tests {
got, err := ParseFormat(tt.in)
if (err != nil) != tt.wantErr || got != tt.want {
t.Errorf("ParseFormat(%q) = %q, %v; erwartet %q, Fehler=%v", tt.in, got, err, tt.want, tt.wantErr)
}
}
}
func TestFormat_ContentType(t *testing.T) {
if got := FormatJSON.ContentType(); got != "application/json" {
t.Errorf("JSON: %q", got)
}
if got := FormatYAML.ContentType(); got != "application/yaml" {
t.Errorf("YAML: %q", got)
}
}