test(e2e): split auth tests, remove sleep/retry skips, and dedupe security coverage

This commit is contained in:
2026-02-10 17:19:00 +01:00
parent 65109a787c
commit 4d2018b20a
6 changed files with 1647 additions and 1847 deletions

View File

@@ -114,84 +114,6 @@ func TestE2E_SearchSanitization(t *testing.T) {
})
}
func TestE2E_SecurityHeaders(t *testing.T) {
ctx := setupTestContext(t)
expectedHeaders := map[string]string{
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"X-XSS-Protection": "1; mode=block",
"Referrer-Policy": "strict-origin-when-cross-origin",
}
type endpointTest struct {
name string
method string
path string
auth bool
body []byte
}
endpoints := []endpointTest{
{name: "health_endpoint", method: "GET", path: "/health", auth: false},
{name: "metrics_endpoint", method: "GET", path: "/metrics", auth: false},
{name: "api_registration", method: "POST", path: "/api/auth/register", auth: false, body: []byte(`{"username":"testuser","email":"test@example.com","password":"StrongPass123!"}`)},
{name: "api_posts", method: "GET", path: "/api/posts", auth: true},
{name: "api_auth_me", method: "GET", path: "/api/auth/me", auth: true},
}
t.Run("security_headers_on_all_endpoints", func(t *testing.T) {
testUser := ctx.createUserWithCleanup(t, "headertest", "StrongPass123!")
var authToken string
authClient, err := ctx.loginUserSafe(t, testUser.Username, testUser.Password)
if err == nil {
authToken = authClient.Token
}
for _, endpoint := range endpoints {
t.Run(endpoint.name, func(t *testing.T) {
var req *http.Request
var err error
if endpoint.body != nil {
req, err = http.NewRequest(endpoint.method, ctx.baseURL+endpoint.path, bytes.NewReader(endpoint.body))
} else {
req, err = http.NewRequest(endpoint.method, ctx.baseURL+endpoint.path, nil)
}
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
if endpoint.auth && authToken != "" {
req.Header.Set("Authorization", "Bearer "+authToken)
}
testutils.WithStandardHeaders(req)
resp, err := ctx.client.Do(req)
if err != nil {
t.Fatalf("Failed to make request: %v", err)
}
defer resp.Body.Close()
for headerName, expectedValue := range expectedHeaders {
actualValue := resp.Header.Get(headerName)
if actualValue != expectedValue {
t.Errorf("Endpoint %s: Expected %s header to be '%s', got '%s'", endpoint.path, headerName, expectedValue, actualValue)
}
}
csp := resp.Header.Get("Content-Security-Policy")
if csp == "" {
t.Errorf("Endpoint %s: Content-Security-Policy header should be present", endpoint.path)
}
})
}
})
}
func TestE2E_SQLInjectionAcrossEndpoints(t *testing.T) {
ctx := setupTestContext(t)
@@ -201,7 +123,7 @@ func TestE2E_SQLInjectionAcrossEndpoints(t *testing.T) {
testUser := ctx.createUserWithCleanup(t, "sqltest", "StrongPass123!")
authClient, err := ctx.loginUserSafe(t, testUser.Username, testUser.Password)
if err != nil {
t.Skipf("Skipping sql injection in post fields test: %v", err)
t.Fatalf("Failed to login for SQL injection post fields test: %v", err)
}
for i, payload := range sqlPayloads {
@@ -313,7 +235,7 @@ func TestE2E_SQLInjectionAcrossEndpoints(t *testing.T) {
testUser := ctx.createUserWithCleanup(t, "sqltest2", "StrongPass123!")
authClient, err := ctx.loginUserSafe(t, testUser.Username, testUser.Password)
if err != nil {
t.Skipf("Skipping sql injection in url fields test: %v", err)
t.Fatalf("Failed to login for SQL injection URL fields test: %v", err)
}
for i, payload := range sqlPayloads {
@@ -349,7 +271,7 @@ func TestE2E_SQLInjectionAcrossEndpoints(t *testing.T) {
testUser := ctx.createUserWithCleanup(t, "sqltest3", "StrongPass123!")
authClient, err := ctx.loginUserSafe(t, testUser.Username, testUser.Password)
if err != nil {
t.Skipf("Skipping sql injection in query parameters test: %v", err)
t.Fatalf("Failed to login for SQL injection query parameter test: %v", err)
}
_ = authClient.CreatePost(t, "Searchable Post", "https://example.com/search", "Content")
@@ -641,16 +563,18 @@ func TestE2E_SecurityHeadersEnhanced(t *testing.T) {
method string
path string
auth bool
body []byte
}{
{"health", "GET", "/health", false},
{"metrics", "GET", "/metrics", false},
{"api_posts", "GET", "/api/posts", true},
{"api_auth_me", "GET", "/api/auth/me", true},
{"health", "GET", "/health", false, nil},
{"metrics", "GET", "/metrics", false, nil},
{"api_registration", "POST", "/api/auth/register", false, []byte(`{"username":"headertestnew","email":"headertestnew@example.com","password":"StrongPass123!"}`)},
{"api_posts", "GET", "/api/posts", true, nil},
{"api_auth_me", "GET", "/api/auth/me", true, nil},
}
for _, endpoint := range endpoints {
t.Run(endpoint.name, func(t *testing.T) {
req, err := http.NewRequest(endpoint.method, ctx.baseURL+endpoint.path, nil)
req, err := http.NewRequest(endpoint.method, ctx.baseURL+endpoint.path, bytes.NewReader(endpoint.body))
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
@@ -710,83 +634,6 @@ func TestE2E_SecurityHeadersEnhanced(t *testing.T) {
})
}
func TestE2E_ParameterizedQueries(t *testing.T) {
ctx := setupTestContext(t)
t.Run("sql_injection_prevention", func(t *testing.T) {
testUser := ctx.createUserWithCleanup(t, "sqltest", "StrongPass123!")
authClient, err := ctx.loginUserSafe(t, testUser.Username, testUser.Password)
if err != nil {
t.Fatalf("Failed to login: %v", err)
}
for i, payload := range testutils.SQLInjectionPayloads {
t.Run(fmt.Sprintf("payload_%d", i), func(t *testing.T) {
postData := map[string]string{
"title": payload,
"url": fmt.Sprintf("https://example.com/test%d", i),
"content": "Test content",
}
req, err := testutils.NewRequestBuilder("POST", ctx.baseURL+"/api/posts").
WithAuth(authClient.Token).
WithJSONBody(postData).
Build()
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
resp, err := ctx.client.Do(req)
if err != nil {
t.Fatalf("Failed to make request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusInternalServerError {
t.Errorf("SQL injection in title caused server error (500). Payload: %s", payload)
}
if resp.StatusCode != http.StatusCreated {
t.Errorf("Expected post creation to succeed (parameterized queries prevent SQL injection), got status: %d", resp.StatusCode)
}
})
}
})
t.Run("search_sanitization", func(t *testing.T) {
testUser := ctx.createUserWithCleanup(t, "searchtest", "StrongPass123!")
authClient, err := ctx.loginUserSafe(t, testUser.Username, testUser.Password)
if err != nil {
t.Fatalf("Failed to login: %v", err)
}
_ = authClient.CreatePost(t, "Searchable Post", "https://example.com/search", "Content")
for i, payload := range testutils.SQLInjectionPayloads {
t.Run(fmt.Sprintf("payload_%d", i), func(t *testing.T) {
searchURL := ctx.baseURL + "/api/posts/search?q=" + url.QueryEscape(payload)
req, err := testutils.NewRequestBuilder("GET", searchURL).
WithAuth(authClient.Token).
Build()
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
resp, err := ctx.client.Do(req)
if err != nil {
t.Fatalf("Failed to make request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusInternalServerError {
t.Errorf("SQL injection in search query caused server error (500). Payload: %s", payload)
}
})
}
})
}
func TestE2E_TokenHashing(t *testing.T) {
ctx := setupTestContext(t)