diff --git a/synkronus-cli/pkg/client/user_test.go b/synkronus-cli/pkg/client/user_test.go new file mode 100644 index 000000000..948cc9ea9 --- /dev/null +++ b/synkronus-cli/pkg/client/user_test.go @@ -0,0 +1,63 @@ +package client + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/OpenDataEnsemble/ode/synkronus-cli/pkg/client/generated" +) + +func TestListUsersParsesSuccessfulJSONResponse(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + t.Errorf("expected GET request, got %s", r.Method) + } + if r.URL.Path != "/api/users" { + t.Errorf("expected /api/users path, got %s", r.URL.Path) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + if _, err := w.Write([]byte(`[ + { + "username": "admin", + "role": "admin", + "created_at": "2026-10-24T12:00:00Z", + "updated_at": "2026-10-24T12:00:00Z" + } + ]`)); err != nil { + t.Errorf("failed to write response: %v", err) + } + })) + defer server.Close() + + api, err := generated.NewClientWithResponses(server.URL) + if err != nil { + t.Fatalf("failed to create generated client: %v", err) + } + + c := &Client{ + BaseURL: server.URL, + APIVersion: "1.0", + api: api, + } + + users, err := c.ListUsers() + if err != nil { + t.Fatalf("ListUsers returned an error: %v", err) + } + + if len(users) != 1 { + t.Fatalf("expected 1 user, got %d", len(users)) + } + + if users[0].Username != "admin" { + t.Errorf("expected username admin, got %s", users[0].Username) + } + + if users[0].Role != generated.UserListItemRole("admin") { + t.Errorf("expected role admin, got %s", users[0].Role) + } +} diff --git a/synkronus/internal/handlers/user.go b/synkronus/internal/handlers/user.go index 54296454d..6d1820bd2 100644 --- a/synkronus/internal/handlers/user.go +++ b/synkronus/internal/handlers/user.go @@ -109,9 +109,7 @@ func (h *Handler) ListUsersHandler(w http.ResponseWriter, r *http.Request) { SendErrorResponse(w, http.StatusBadRequest, err, err.Error()) return } - if err := json.NewEncoder(w).Encode(userList); err != nil { - h.log.Error("Failed to encode user list response", "error", err) - } + SendJSONResponse(w, http.StatusOK, userList) } // ChangePasswordRequest represents the request body for changing password diff --git a/synkronus/internal/handlers/user_test.go b/synkronus/internal/handlers/user_test.go index 83bba4a64..eb57f4d63 100644 --- a/synkronus/internal/handlers/user_test.go +++ b/synkronus/internal/handlers/user_test.go @@ -159,6 +159,23 @@ func TestResetPasswordHandler(t *testing.T) { } } +func TestListUsersHandlerReturnsJSONContentType(t *testing.T) { + h, mockUserService := userHandlerTestHelper() + mockUserService.AddUser(&models.User{ + Username: "admin", + Role: models.RoleAdmin, + }) + + r := httptest.NewRequest(http.MethodGet, "/api/users", nil) + w := httptest.NewRecorder() + + h.ListUsersHandler(w, r) + + resp := w.Result() + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) +} + func TestChangePasswordHandler(t *testing.T) { h, mockUserService := userHandlerTestHelper() mockUserService.AddUser(&models.User{Username: "changepw", PasswordHash: "oldpw", Role: models.RoleReadOnly})