package dav import ( "testing" tlsct "git.happydns.org/checker-tls/contract" ) // parseAll decodes DiscoverEntries output via the TLS contract. Malformed // entries fail the test so we notice drift quickly. func parseAll(t *testing.T, obs *Observation) []tlsct.TLSEndpoint { t.Helper() entries := DiscoverEntries(obs) eps, warnings := tlsct.ParseEntries(entries) if len(warnings) != 0 { t.Fatalf("unexpected decode warnings: %v", warnings) } out := make([]tlsct.TLSEndpoint, len(eps)) for i, e := range eps { if e.Ref == "" { t.Errorf("entry %d has empty Ref", i) } out[i] = e.Endpoint } return out } func TestDiscoverEntries_contextURLOnly(t *testing.T) { obs := &Observation{ Discovery: DiscoveryResult{ContextURL: "https://dav.example.com/caldav/"}, } got := parseAll(t, obs) if len(got) != 1 { t.Fatalf("got %d endpoints, want 1: %+v", len(got), got) } if got[0].Host != "dav.example.com" || got[0].Port != 443 { t.Errorf("unexpected endpoint: %+v", got[0]) } // Direct TLS; no STARTTLS upgrade. if got[0].STARTTLS != "" { t.Errorf("STARTTLS = %q, want empty (direct TLS)", got[0].STARTTLS) } // SNI must be set unconditionally, even when it is equal to Host. if got[0].SNI != "dav.example.com" { t.Errorf("SNI = %q, want dav.example.com", got[0].SNI) } } func TestDiscoverEntries_nonDefaultPort(t *testing.T) { obs := &Observation{ Discovery: DiscoveryResult{ContextURL: "https://dav.example.com:8443/caldav/"}, } got := parseAll(t, obs) if len(got) != 1 || got[0].Port != 8443 { t.Fatalf("unexpected: %+v", got) } } func TestDiscoverEntries_srvTargets(t *testing.T) { // SRV pointing to a different name than the domain → we must surface // the SRV target too, because that's the hostname the cert needs to // cover. obs := &Observation{ Discovery: DiscoveryResult{ ContextURL: "https://dav.example.com/caldav/", SecureSRV: []SRVRecord{ {Target: "dav-backend-1.example.net", Port: 443}, {Target: "dav-backend-2.example.net", Port: 443}, {Target: "dav.example.com", Port: 443}, // duplicate of context → deduped }, }, } got := parseAll(t, obs) if len(got) != 3 { t.Fatalf("expected 3 unique endpoints, got %d: %+v", len(got), got) } hosts := map[string]bool{} for _, e := range got { hosts[e.Host] = true if e.SNI != e.Host { t.Errorf("endpoint %+v: SNI=%q, want %q (equal to Host)", e, e.SNI, e.Host) } } for _, want := range []string{"dav.example.com", "dav-backend-1.example.net", "dav-backend-2.example.net"} { if !hosts[want] { t.Errorf("missing host %q in %+v", want, got) } } } func TestDiscoverEntries_emptyOnNoContextURL(t *testing.T) { if got := DiscoverEntries(&Observation{}); got != nil { t.Errorf("expected nil, got %+v", got) } if got := DiscoverEntries(nil); got != nil { t.Errorf("expected nil for nil obs, got %+v", got) } }