package dav import ( "context" "net/http" "net/http/httptest" "net/url" "strings" "testing" ) // TestDiscover_wellKnownRedirect walks the happy path: /.well-known/caldav // returns a 301 to the real context URL. func TestDiscover_wellKnownRedirect(t *testing.T) { var hits []string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { hits = append(hits, r.URL.Path) if r.URL.Path == "/.well-known/caldav" { http.Redirect(w, r, "/dav/", http.StatusMovedPermanently) return } w.WriteHeader(http.StatusOK) })) t.Cleanup(srv.Close) // Route "example.test/.well-known/caldav" through the test server. c := srv.Client() c.Transport = rewriteTransport{base: srv.URL, next: c.Transport} res := Discover(context.Background(), c, KindCalDAV, "example.test", "") if res.Source != "well-known" { t.Errorf("source = %q, want well-known", res.Source) } if !strings.HasSuffix(res.ContextURL, "/dav/") { t.Errorf("context URL = %q", res.ContextURL) } if res.WellKnownCode != 301 { t.Errorf("expected 301 captured, got %d", res.WellKnownCode) } if len(res.WellKnownChain) < 1 { t.Error("expected redirect chain to be recorded") } } // TestDiscover_wellKnownReturns200 reproduces the most common misconfig: the // server returns 200 on /.well-known/caldav instead of redirecting. Discover // must still set ContextURL (to the well-known URL) but WellKnownCode=200 so // the rule can emit the warning callout. func TestDiscover_wellKnownReturns200(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })) t.Cleanup(srv.Close) c := srv.Client() c.Transport = rewriteTransport{base: srv.URL, next: c.Transport} res := Discover(context.Background(), c, KindCardDAV, "example.test", "") if res.WellKnownCode != 200 { t.Errorf("well-known code = %d, want 200", res.WellKnownCode) } if res.ContextURL == "" { t.Error("expected ContextURL to fall back to the well-known URL") } } func TestDiscover_explicitOverride(t *testing.T) { res := Discover(context.Background(), http.DefaultClient, KindCalDAV, "example.test", "https://custom.example/dav/") if res.Source != "explicit" { t.Errorf("source: %q", res.Source) } if res.ContextURL != "https://custom.example/dav/" { t.Errorf("ctx: %q", res.ContextURL) } if res.WellKnownURL != "" { t.Errorf("should not have probed well-known, got %q", res.WellKnownURL) } } func TestDiscover_redirectLoop(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Always redirect to itself → triggers "too many redirects". http.Redirect(w, r, r.URL.Path, http.StatusFound) })) t.Cleanup(srv.Close) c := srv.Client() c.Transport = rewriteTransport{base: srv.URL, next: c.Transport} res := Discover(context.Background(), c, KindCalDAV, "example.test", "") if res.WellKnownError == "" { t.Error("expected well-known error, got none") } } // rewriteTransport rewrites any request URL's host to point at base so we can // exercise Discover() without setting up DNS. It preserves the original path. type rewriteTransport struct { base string next http.RoundTripper } func (r rewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) { baseURL, _ := url.Parse(r.base) req.URL.Scheme = baseURL.Scheme req.URL.Host = baseURL.Host next := r.next if next == nil { next = http.DefaultTransport } return next.RoundTrip(req) }