|
|
|
@ -21,6 +21,7 @@ import (
|
|
|
|
sharedtypes "knowfoolery/backend/shared/domain/types"
|
|
|
|
sharedtypes "knowfoolery/backend/shared/domain/types"
|
|
|
|
sharedmetrics "knowfoolery/backend/shared/infra/observability/metrics"
|
|
|
|
sharedmetrics "knowfoolery/backend/shared/infra/observability/metrics"
|
|
|
|
"knowfoolery/backend/shared/infra/utils/validation"
|
|
|
|
"knowfoolery/backend/shared/infra/utils/validation"
|
|
|
|
|
|
|
|
sharedhttpx "knowfoolery/backend/shared/testutil/httpx"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// inMemoryRepo is a lightweight repository double for HTTP integration tests.
|
|
|
|
// inMemoryRepo is a lightweight repository double for HTTP integration tests.
|
|
|
|
@ -230,13 +231,13 @@ func TestRegisterAndCRUD(t *testing.T) {
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/users/register", bytes.NewReader(payload))
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/users/register", bytes.NewReader(payload))
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
resp := mustTest(t, app, req)
|
|
|
|
resp := sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusOK, "register failed")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusOK, "register failed")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/users/user-1", nil)
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/users/user-1", nil)
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
resp = mustTest(t, app, req)
|
|
|
|
resp = sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusOK, "get failed")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusOK, "get failed")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
updatePayload, _ := json.Marshal(map[string]any{
|
|
|
|
updatePayload, _ := json.Marshal(map[string]any{
|
|
|
|
@ -247,13 +248,13 @@ func TestRegisterAndCRUD(t *testing.T) {
|
|
|
|
req = httptest.NewRequest(http.MethodPut, "/users/user-1", bytes.NewReader(updatePayload))
|
|
|
|
req = httptest.NewRequest(http.MethodPut, "/users/user-1", bytes.NewReader(updatePayload))
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
resp = mustTest(t, app, req)
|
|
|
|
resp = sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusOK, "update failed")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusOK, "update failed")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
req = httptest.NewRequest(http.MethodDelete, "/users/user-1", nil)
|
|
|
|
req = httptest.NewRequest(http.MethodDelete, "/users/user-1", nil)
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
resp = mustTest(t, app, req)
|
|
|
|
resp = sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusNoContent, "delete failed")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusNoContent, "delete failed")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -262,32 +263,32 @@ func TestAuthGuardsAndAdminRoutes(t *testing.T) {
|
|
|
|
app, _ := setupApp(t)
|
|
|
|
app, _ := setupApp(t)
|
|
|
|
|
|
|
|
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/users/user-1", nil)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/users/user-1", nil)
|
|
|
|
resp := mustTest(t, app, req)
|
|
|
|
resp := sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusUnauthorized, "expected unauthorized")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusUnauthorized, "expected unauthorized")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/users/user-2", nil)
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/users/user-2", nil)
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
resp = mustTest(t, app, req)
|
|
|
|
resp = sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusForbidden, "expected forbidden")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusForbidden, "expected forbidden")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/admin/users", nil)
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/admin/users", nil)
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
req.Header.Set("Authorization", "Bearer user-1")
|
|
|
|
resp = mustTest(t, app, req)
|
|
|
|
resp = sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusForbidden, "expected admin forbidden")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusForbidden, "expected admin forbidden")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/admin/users", nil)
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/admin/users", nil)
|
|
|
|
req.Header.Set("Authorization", "Bearer admin")
|
|
|
|
req.Header.Set("Authorization", "Bearer admin")
|
|
|
|
resp = mustTest(t, app, req)
|
|
|
|
resp = sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusOK, "expected admin list ok")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusOK, "expected admin list ok")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
req = httptest.NewRequest(http.MethodPost, "/admin/users/user-2/export", nil)
|
|
|
|
req = httptest.NewRequest(http.MethodPost, "/admin/users/user-2/export", nil)
|
|
|
|
req.Header.Set("Authorization", "Bearer admin")
|
|
|
|
req.Header.Set("Authorization", "Bearer admin")
|
|
|
|
resp = mustTest(t, app, req)
|
|
|
|
resp = sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusOK, "expected export ok")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusOK, "expected export ok")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -296,26 +297,7 @@ func TestMetricsEndpoint(t *testing.T) {
|
|
|
|
app, _ := setupApp(t)
|
|
|
|
app, _ := setupApp(t)
|
|
|
|
|
|
|
|
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
|
|
|
resp := mustTest(t, app, req)
|
|
|
|
resp := sharedhttpx.MustTest(t, app, req)
|
|
|
|
assertStatusAndClose(t, resp, http.StatusOK, "metrics failed")
|
|
|
|
sharedhttpx.AssertStatusAndClose(t, resp, http.StatusOK, "metrics failed")
|
|
|
|
defer resp.Body.Close()
|
|
|
|
defer resp.Body.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// mustTest executes a test request and fails immediately on transport errors.
|
|
|
|
|
|
|
|
func mustTest(t *testing.T, app *fiber.App, req *http.Request) *http.Response {
|
|
|
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
resp, err := app.Test(req)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
t.Fatalf("app.Test failed: %v", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// assertStatusAndClose checks the HTTP status and always closes the response body.
|
|
|
|
|
|
|
|
func assertStatusAndClose(t *testing.T, resp *http.Response, want int, msg string) {
|
|
|
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
|
|
|
|
if resp.StatusCode != want {
|
|
|
|
|
|
|
|
t.Fatalf("%s: status=%d want=%d", msg, resp.StatusCode, want)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|