package agent import ( "context" "net/http" "net/http/httptest" "reflect" "testing" "time" ) const page = ` Shop - Willkommen

Hallo

Impressum

` func healthServer(t *testing.T, status int, body string, delay time.Duration) string { t.Helper() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if delay > 0 { select { case <-time.After(delay): case <-r.Context().Done(): return } } w.WriteHeader(status) w.Write([]byte(body)) })) t.Cleanup(srv.Close) return srv.URL } func TestCheckHealth(t *testing.T) { ok := healthServer(t, 200, page, 0) tests := []struct { name string url string spec HealthSpec ok bool }{ {"nur Status", ok, HealthSpec{ExpectStatus: 200}, true}, {"Titel passt (Leerraum, Großschreibung des Tags egal)", ok, HealthSpec{ExpectStatus: 200, ExpectTitle: "Shop - Willkommen"}, true}, {"Tag mit Text, verschachtelt", ok, HealthSpec{ExpectStatus: 200, ExpectContains: &ContainsSpec{Tag: "H2", Text: "Impressum"}}, true}, {"falscher Status", healthServer(t, 500, page, 0), HealthSpec{ExpectStatus: 200}, false}, {"anderer erwarteter Status", healthServer(t, 204, "", 0), HealthSpec{ExpectStatus: 204}, true}, {"Titel weicht ab", ok, HealthSpec{ExpectStatus: 200, ExpectTitle: "Wartung"}, false}, {"Text fehlt", ok, HealthSpec{ExpectStatus: 200, ExpectContains: &ContainsSpec{Tag: "h2", Text: "Datenschutz"}}, false}, {"Text im falschen Tag", ok, HealthSpec{ExpectStatus: 200, ExpectContains: &ContainsSpec{Tag: "h1", Text: "Impressum"}}, false}, {"Zeitüberschreitung", healthServer(t, 200, page, time.Second), HealthSpec{ExpectStatus: 200, Timeout: Duration{50 * time.Millisecond}}, false}, {"nicht erreichbar", "http://127.0.0.1:1", HealthSpec{ExpectStatus: 200}, false}, } for _, tt := range tests { if tt.spec.Timeout.Duration == 0 { tt.spec.Timeout = Duration{2 * time.Second} } tt.spec.URL = tt.url err := checkHealth(context.Background(), http.DefaultClient, tt.spec) if (err == nil) != tt.ok { t.Errorf("%s: err=%v, erwartet ok=%v", tt.name, err, tt.ok) } } } // Ausfall erst nach N Fehlschlägen in Folge, Erholung nach einem Erfolg – // gegen Flattern. func TestHealthTracker(t *testing.T) { var tr healthTracker steps := []struct { ok bool changed bool down []string }{ {true, false, nil}, {false, false, nil}, {true, false, nil}, // Zähler zurückgesetzt {false, false, nil}, {false, true, []string{"shop"}}, {false, false, []string{"shop"}}, {true, true, nil}, } for i, s := range steps { if changed := tr.report("shop", 2, s.ok); changed != s.changed { t.Errorf("Schritt %d: changed=%v, erwartet %v", i, changed, s.changed) } if got := tr.down(); !reflect.DeepEqual(got, s.down) { t.Errorf("Schritt %d: down=%v, erwartet %v", i, got, s.down) } } tr.report("a", 1, false) tr.report("b", 1, false) if got := tr.down(); !reflect.DeepEqual(got, []string{"a", "b"}) { t.Errorf("sortiert: %v", got) } tr.retain(map[string]bool{"b": true}) if got := tr.down(); !reflect.DeepEqual(got, []string{"b"}) { t.Errorf("nach retain: %v", got) } }