package service import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "net/url" "strings" "testing" ) // clientForHandler returns an http.Client that routes requests to the given handler // without real network sockets. func clientForHandler(h http.Handler) *http.Client { return &http.Client{ Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) { // Clone request body for handler var bodyBytes []byte if req.Body != nil { bodyBytes, _ = io.ReadAll(req.Body) } r := httptest.NewRequest(req.Method, req.URL.String(), bytes.NewReader(bodyBytes)) r.Header = req.Header.Clone() w := httptest.NewRecorder() h.ServeHTTP(w, r) return w.Result(), nil }), } } type roundTripperFunc func(req *http.Request) (*http.Response, error) func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) } func TestUpdateUserPassword_Success(t *testing.T) { const ( loginID = "user@example.com" identityID = "7f0dc8c3-9d5d-4f57-b3d1-123456789abc" newPassword = "Sup3rStr0ng!Pass#2026" ) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch { case strings.HasPrefix(r.URL.Path, "/admin/identities") && r.Method == http.MethodGet: q := r.URL.Query() if got := q.Get("credentials_identifier"); got != loginID { t.Fatalf("expected credentials_identifier=%s, got=%s", loginID, got) } _ = json.NewEncoder(w).Encode([]map[string]string{ {"id": identityID}, }) return case r.URL.Path == "/admin/identities/"+identityID && r.Method == http.MethodPatch: body, _ := io.ReadAll(r.Body) if !strings.Contains(string(body), newPassword) { t.Fatalf("payload missing new password, body=%s", string(body)) } w.WriteHeader(http.StatusOK) return default: t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String()) } }) provider := &OryProvider{ KratosAdminURL: "http://kratos-admin.local", HTTPClient: clientForHandler(handler), } if err := provider.UpdateUserPassword(loginID, newPassword, nil); err != nil { t.Fatalf("UpdateUserPassword returned error: %v", err) } } func TestUpdateUserPassword_NotFound(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/admin/identities") && r.Method == http.MethodGet { http.NotFound(w, r) return } t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String()) }) provider := &OryProvider{ KratosAdminURL: "http://kratos-admin.local", HTTPClient: clientForHandler(handler), } err := provider.UpdateUserPassword("user@example.com", "Sup3rStr0ng!Pass#2026", nil) if err == nil || !strings.Contains(err.Error(), "identity not found") { t.Fatalf("expected identity not found error, got: %v", err) } } func TestUpdateUserPassword_ServerError(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch { case strings.HasPrefix(r.URL.Path, "/admin/identities") && r.Method == http.MethodGet: _ = json.NewEncoder(w).Encode([]map[string]string{ {"id": "abc"}, }) return case r.URL.Path == "/admin/identities/abc" && r.Method == http.MethodPatch: http.Error(w, "boom", http.StatusInternalServerError) return default: t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String()) } }) provider := &OryProvider{ KratosAdminURL: "http://kratos-admin.local", HTTPClient: clientForHandler(handler), } err := provider.UpdateUserPassword("user@example.com", "Sup3rStr0ng!Pass#2026", nil) if err == nil || !strings.Contains(err.Error(), "password update failed") { t.Fatalf("expected server error, got: %v", err) } } func TestFindIdentityID_QueryEncoding(t *testing.T) { loginID := "user+alias@example.com" handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { values, _ := url.ParseQuery(r.URL.RawQuery) if values.Get("credentials_identifier") != loginID { t.Fatalf("expected credentials_identifier=%s, got=%s", loginID, values.Get("credentials_identifier")) } _ = json.NewEncoder(w).Encode([]map[string]string{ {"id": "id-123"}, }) }) provider := &OryProvider{ KratosAdminURL: "http://kratos-admin.local", HTTPClient: clientForHandler(handler), } id, err := provider.findIdentityID(loginID) if err != nil { t.Fatalf("findIdentityID returned error: %v", err) } if id != "id-123" { t.Fatalf("expected id-123, got %s", id) } }