Update tests to use test user struct

This commit is contained in:
2024-12-08 15:03:39 +01:00
parent 2e1ccb45d6
commit 69af630332
7 changed files with 200 additions and 209 deletions

View File

@@ -35,7 +35,7 @@ func TestAdminHandlers_Integration(t *testing.T) {
t.Run("user management", func(t *testing.T) { t.Run("user management", func(t *testing.T) {
t.Run("list users", func(t *testing.T) { t.Run("list users", func(t *testing.T) {
// Test with admin session // Test with admin session
rr := h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.AdminSession) rr := h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.AdminTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var users []*models.User var users []*models.User
@@ -44,11 +44,11 @@ func TestAdminHandlers_Integration(t *testing.T) {
// Should have at least our admin and regular test users // Should have at least our admin and regular test users
assert.GreaterOrEqual(t, len(users), 2) assert.GreaterOrEqual(t, len(users), 2)
assert.True(t, containsUser(users, h.AdminUser), "Admin user not found in users list") assert.True(t, containsUser(users, h.AdminTestUser.userModel), "Admin user not found in users list")
assert.True(t, containsUser(users, h.RegularUser), "Regular user not found in users list") assert.True(t, containsUser(users, h.RegularTestUser.userModel), "Regular user not found in users list")
// Test with non-admin session // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.RegularTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
// Test without session // Test without session
@@ -65,7 +65,7 @@ func TestAdminHandlers_Integration(t *testing.T) {
} }
// Test with admin session // Test with admin session
rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var createdUser models.User var createdUser models.User
@@ -77,7 +77,7 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.NotZero(t, createdUser.LastWorkspaceID) assert.NotZero(t, createdUser.LastWorkspaceID)
// Test duplicate email // Test duplicate email
rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession) rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminTestUser)
assert.Equal(t, http.StatusConflict, rr.Code) assert.Equal(t, http.StatusConflict, rr.Code)
// Test invalid request (missing required fields) // Test invalid request (missing required fields)
@@ -85,44 +85,44 @@ func TestAdminHandlers_Integration(t *testing.T) {
Email: "invalid@test.com", Email: "invalid@test.com",
// Missing password and role // Missing password and role
} }
rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", invalidReq, h.AdminSession) rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", invalidReq, h.AdminTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
// Test with non-admin session // Test with non-admin session
rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.RegularSession) rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.RegularTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
t.Run("get user", func(t *testing.T) { t.Run("get user", func(t *testing.T) {
path := fmt.Sprintf("/api/v1/admin/users/%d", h.RegularUser.ID) path := fmt.Sprintf("/api/v1/admin/users/%d", h.RegularTestUser.session.UserID)
// Test with admin session // Test with admin session
rr := h.makeRequest(t, http.MethodGet, path, nil, h.AdminSession) rr := h.makeRequest(t, http.MethodGet, path, nil, h.AdminTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var user models.User var user models.User
err := json.NewDecoder(rr.Body).Decode(&user) err := json.NewDecoder(rr.Body).Decode(&user)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, h.RegularUser.ID, user.ID) assert.Equal(t, h.RegularTestUser.session.UserID, user.ID)
// Test non-existent user // Test non-existent user
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users/999999", nil, h.AdminSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users/999999", nil, h.AdminTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
// Test with non-admin session // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, path, nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, path, nil, h.RegularTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
t.Run("update user", func(t *testing.T) { t.Run("update user", func(t *testing.T) {
path := fmt.Sprintf("/api/v1/admin/users/%d", h.RegularUser.ID) path := fmt.Sprintf("/api/v1/admin/users/%d", h.RegularTestUser.session.UserID)
updateReq := handlers.UpdateUserRequest{ updateReq := handlers.UpdateUserRequest{
DisplayName: "Updated Name", DisplayName: "Updated Name",
Role: models.RoleViewer, Role: models.RoleViewer,
} }
// Test with admin session // Test with admin session
rr := h.makeRequest(t, http.MethodPut, path, updateReq, h.AdminSession) rr := h.makeRequest(t, http.MethodPut, path, updateReq, h.AdminTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var updatedUser models.User var updatedUser models.User
@@ -132,7 +132,7 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.Equal(t, updateReq.Role, updatedUser.Role) assert.Equal(t, updateReq.Role, updatedUser.Role)
// Test with non-admin session // Test with non-admin session
rr = h.makeRequest(t, http.MethodPut, path, updateReq, h.RegularSession) rr = h.makeRequest(t, http.MethodPut, path, updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
@@ -145,7 +145,7 @@ func TestAdminHandlers_Integration(t *testing.T) {
Role: models.RoleEditor, Role: models.RoleEditor,
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var createdUser models.User var createdUser models.User
@@ -155,20 +155,20 @@ func TestAdminHandlers_Integration(t *testing.T) {
path := fmt.Sprintf("/api/v1/admin/users/%d", createdUser.ID) path := fmt.Sprintf("/api/v1/admin/users/%d", createdUser.ID)
// Test deleting own account (should fail) // Test deleting own account (should fail)
adminPath := fmt.Sprintf("/api/v1/admin/users/%d", h.AdminUser.ID) adminPath := fmt.Sprintf("/api/v1/admin/users/%d", h.AdminTestUser.session.UserID)
rr = h.makeRequest(t, http.MethodDelete, adminPath, nil, h.AdminSession) rr = h.makeRequest(t, http.MethodDelete, adminPath, nil, h.AdminTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
// Test with admin session // Test with admin session
rr = h.makeRequest(t, http.MethodDelete, path, nil, h.AdminSession) rr = h.makeRequest(t, http.MethodDelete, path, nil, h.AdminTestUser)
assert.Equal(t, http.StatusNoContent, rr.Code) assert.Equal(t, http.StatusNoContent, rr.Code)
// Verify user is deleted // Verify user is deleted
rr = h.makeRequest(t, http.MethodGet, path, nil, h.AdminSession) rr = h.makeRequest(t, http.MethodGet, path, nil, h.AdminTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
// Test with non-admin session // Test with non-admin session
rr = h.makeRequest(t, http.MethodDelete, path, nil, h.RegularSession) rr = h.makeRequest(t, http.MethodDelete, path, nil, h.RegularTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
}) })
@@ -177,15 +177,15 @@ func TestAdminHandlers_Integration(t *testing.T) {
t.Run("list workspaces", func(t *testing.T) { t.Run("list workspaces", func(t *testing.T) {
// Create a test workspace first // Create a test workspace first
workspace := &models.Workspace{ workspace := &models.Workspace{
UserID: h.RegularUser.ID, UserID: h.RegularTestUser.session.UserID,
Name: "Test Workspace", Name: "Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Test with admin session // Test with admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.AdminSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.AdminTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var workspaces []*handlers.WorkspaceStats var workspaces []*handlers.WorkspaceStats
@@ -207,7 +207,7 @@ func TestAdminHandlers_Integration(t *testing.T) {
} }
// Test with non-admin session // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.RegularTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
}) })
@@ -215,14 +215,14 @@ func TestAdminHandlers_Integration(t *testing.T) {
t.Run("system stats", func(t *testing.T) { t.Run("system stats", func(t *testing.T) {
// Create some test data // Create some test data
workspace := &models.Workspace{ workspace := &models.Workspace{
UserID: h.RegularUser.ID, UserID: h.RegularTestUser.session.UserID,
Name: "Stats Test Workspace", Name: "Stats Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Test with admin session // Test with admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.AdminSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.AdminTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var stats handlers.SystemStats var stats handlers.SystemStats
@@ -237,7 +237,7 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.GreaterOrEqual(t, stats.TotalSize, int64(0)) assert.GreaterOrEqual(t, stats.TotalSize, int64(0))
// Test with non-admin session // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.RegularTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
} }

View File

@@ -40,17 +40,17 @@ func TestAuthHandlers_Integration(t *testing.T) {
case "access_token": case "access_token":
foundAccessToken = true foundAccessToken = true
assert.True(t, cookie.HttpOnly, "access_token cookie must be HttpOnly") assert.True(t, cookie.HttpOnly, "access_token cookie must be HttpOnly")
assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite) assert.Equal(t, http.SameSiteLaxMode, cookie.SameSite)
assert.Equal(t, 900, cookie.MaxAge) // 15 minutes assert.Equal(t, 900, cookie.MaxAge) // 15 minutes
case "refresh_token": case "refresh_token":
foundRefreshToken = true foundRefreshToken = true
assert.True(t, cookie.HttpOnly, "refresh_token cookie must be HttpOnly") assert.True(t, cookie.HttpOnly, "refresh_token cookie must be HttpOnly")
assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite) assert.Equal(t, http.SameSiteLaxMode, cookie.SameSite)
assert.Equal(t, 604800, cookie.MaxAge) // 7 days assert.Equal(t, 604800, cookie.MaxAge) // 7 days
case "csrf_token": case "csrf_token":
foundCSRF = true foundCSRF = true
assert.False(t, cookie.HttpOnly, "csrf_token cookie must not be HttpOnly") assert.False(t, cookie.HttpOnly, "csrf_token cookie must not be HttpOnly")
assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite) assert.Equal(t, http.SameSiteLaxMode, cookie.SameSite)
assert.Equal(t, 900, cookie.MaxAge) // 15 minutes assert.Equal(t, 900, cookie.MaxAge) // 15 minutes
} }
} }
@@ -148,7 +148,8 @@ func TestAuthHandlers_Integration(t *testing.T) {
t.Run("successful token refresh", func(t *testing.T) { t.Run("successful token refresh", func(t *testing.T) {
// Need lower level helpers for precise cookie control // Need lower level helpers for precise cookie control
req := h.newRequest(t, http.MethodPost, "/api/v1/auth/refresh", nil) req := h.newRequest(t, http.MethodPost, "/api/v1/auth/refresh", nil)
h.addAuthCookies(t, req, h.RegularSession, true) // Adds both tokens h.addAuthCookies(t, req, h.RegularTestUser) // Adds both tokens
h.addCSRFCookie(t, req)
rr := h.executeRequest(req) rr := h.executeRequest(req)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
@@ -181,8 +182,7 @@ func TestAuthHandlers_Integration(t *testing.T) {
name: "missing refresh token cookie", name: "missing refresh token cookie",
setup: func(req *http.Request) { setup: func(req *http.Request) {
// Only add access token // Only add access token
token, _ := h.JWTManager.GenerateAccessToken(h.RegularSession.UserID, "admin") req.AddCookie(h.CookieManager.GenerateAccessTokenCookie(h.RegularTestUser.accessToken))
req.AddCookie(h.CookieManager.GenerateAccessTokenCookie(token))
}, },
wantCode: http.StatusBadRequest, wantCode: http.StatusBadRequest,
}, },
@@ -191,11 +191,16 @@ func TestAuthHandlers_Integration(t *testing.T) {
setup: func(req *http.Request) { setup: func(req *http.Request) {
expiredSession := &models.Session{ expiredSession := &models.Session{
ID: "expired", ID: "expired",
UserID: h.RegularUser.ID, UserID: h.RegularTestUser.session.UserID,
RefreshToken: "expired-token", RefreshToken: "expired-token",
ExpiresAt: time.Now().Add(-1 * time.Hour), ExpiresAt: time.Now().Add(-1 * time.Hour),
} }
h.addAuthCookies(t, req, expiredSession, true) expiredSessionUser := &testUser{
userModel: h.RegularTestUser.userModel,
accessToken: h.RegularTestUser.accessToken,
session: expiredSession,
}
h.addAuthCookies(t, req, expiredSessionUser)
}, },
wantCode: http.StatusUnauthorized, wantCode: http.StatusUnauthorized,
}, },
@@ -226,7 +231,8 @@ func TestAuthHandlers_Integration(t *testing.T) {
t.Run("successful logout", func(t *testing.T) { t.Run("successful logout", func(t *testing.T) {
// Need CSRF token for POST request // Need CSRF token for POST request
req := h.newRequest(t, http.MethodPost, "/api/v1/auth/logout", nil) req := h.newRequest(t, http.MethodPost, "/api/v1/auth/logout", nil)
csrfToken := h.addAuthCookies(t, req, h.RegularSession, true) h.addAuthCookies(t, req, h.RegularTestUser)
csrfToken := h.addCSRFCookie(t, req)
req.Header.Set("X-CSRF-Token", csrfToken) req.Header.Set("X-CSRF-Token", csrfToken)
rr := h.executeRequest(req) rr := h.executeRequest(req)
require.Equal(t, http.StatusNoContent, rr.Code) require.Equal(t, http.StatusNoContent, rr.Code)
@@ -238,7 +244,7 @@ func TestAuthHandlers_Integration(t *testing.T) {
} }
// Verify session is actually invalidated // Verify session is actually invalidated
rr = h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularTestUser)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -251,7 +257,8 @@ func TestAuthHandlers_Integration(t *testing.T) {
{ {
name: "missing CSRF token", name: "missing CSRF token",
setup: func(req *http.Request) { setup: func(req *http.Request) {
h.addAuthCookies(t, req, h.RegularSession, true) h.addAuthCookies(t, req, h.RegularTestUser)
h.addCSRFCookie(t, req)
// Deliberately not setting X-CSRF-Token header // Deliberately not setting X-CSRF-Token header
}, },
wantCode: http.StatusForbidden, wantCode: http.StatusForbidden,
@@ -259,7 +266,8 @@ func TestAuthHandlers_Integration(t *testing.T) {
{ {
name: "mismatched CSRF token", name: "mismatched CSRF token",
setup: func(req *http.Request) { setup: func(req *http.Request) {
h.addAuthCookies(t, req, h.RegularSession, true) h.addAuthCookies(t, req, h.RegularTestUser)
h.addCSRFCookie(t, req)
req.Header.Set("X-CSRF-Token", "wrong-token") req.Header.Set("X-CSRF-Token", "wrong-token")
}, },
wantCode: http.StatusForbidden, wantCode: http.StatusForbidden,
@@ -286,13 +294,13 @@ func TestAuthHandlers_Integration(t *testing.T) {
t.Run("get current user", func(t *testing.T) { t.Run("get current user", func(t *testing.T) {
t.Run("successful get current user", func(t *testing.T) { t.Run("successful get current user", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var user models.User var user models.User
err := json.NewDecoder(rr.Body).Decode(&user) err := json.NewDecoder(rr.Body).Decode(&user)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, h.RegularUser.Email, user.Email) assert.Equal(t, h.RegularTestUser.userModel.Email, user.Email)
}) })
t.Run("auth edge cases", func(t *testing.T) { t.Run("auth edge cases", func(t *testing.T) {
@@ -317,7 +325,12 @@ func TestAuthHandlers_Integration(t *testing.T) {
RefreshToken: "invalid", RefreshToken: "invalid",
ExpiresAt: time.Now().Add(time.Hour), ExpiresAt: time.Now().Add(time.Hour),
} }
h.addAuthCookies(t, req, invalidSession, false) invalidSessionUser := &testUser{
userModel: h.RegularTestUser.userModel,
accessToken: h.RegularTestUser.accessToken,
session: invalidSession,
}
h.addAuthCookies(t, req, invalidSessionUser)
}, },
wantCode: http.StatusUnauthorized, wantCode: http.StatusUnauthorized,
}, },
@@ -326,11 +339,16 @@ func TestAuthHandlers_Integration(t *testing.T) {
setup: func(req *http.Request) { setup: func(req *http.Request) {
expiredSession := &models.Session{ expiredSession := &models.Session{
ID: "expired", ID: "expired",
UserID: h.RegularUser.ID, UserID: h.RegularTestUser.session.UserID,
RefreshToken: "expired-token", RefreshToken: "expired-token",
ExpiresAt: time.Now().Add(-1 * time.Hour), ExpiresAt: time.Now().Add(-1 * time.Hour),
} }
h.addAuthCookies(t, req, expiredSession, false) expiredSessionUser := &testUser{
userModel: h.RegularTestUser.userModel,
accessToken: h.RegularTestUser.accessToken,
session: expiredSession,
}
h.addAuthCookies(t, req, expiredSessionUser)
}, },
wantCode: http.StatusUnauthorized, wantCode: http.StatusUnauthorized,
}, },

View File

@@ -24,10 +24,10 @@ func TestFileHandlers_Integration(t *testing.T) {
t.Run("file operations", func(t *testing.T) { t.Run("file operations", func(t *testing.T) {
// Setup: Create a workspace first // Setup: Create a workspace first
workspace := &models.Workspace{ workspace := &models.Workspace{
UserID: h.RegularUser.ID, UserID: h.RegularTestUser.session.UserID,
Name: "File Test Workspace", Name: "File Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
err := json.NewDecoder(rr.Body).Decode(workspace) err := json.NewDecoder(rr.Body).Decode(workspace)
@@ -37,7 +37,7 @@ func TestFileHandlers_Integration(t *testing.T) {
baseURL := fmt.Sprintf("/api/v1/workspaces/%s/files", url.PathEscape(workspace.Name)) baseURL := fmt.Sprintf("/api/v1/workspaces/%s/files", url.PathEscape(workspace.Name))
t.Run("list empty directory", func(t *testing.T) { t.Run("list empty directory", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var files []storage.FileNode var files []storage.FileNode
@@ -51,16 +51,16 @@ func TestFileHandlers_Integration(t *testing.T) {
filePath := "test.md" filePath := "test.md"
// Save file // Save file
rr := h.makeRequestRaw(t, http.MethodPost, baseURL+"/"+filePath, strings.NewReader(content), h.RegularSession) rr := h.makeRequestRaw(t, http.MethodPost, baseURL+"/"+filePath, strings.NewReader(content), h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Get file content // Get file content
rr = h.makeRequest(t, http.MethodGet, baseURL+"/"+filePath, nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, baseURL+"/"+filePath, nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, content, rr.Body.String()) assert.Equal(t, content, rr.Body.String())
// List directory should now show the file // List directory should now show the file
rr = h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var files []storage.FileNode var files []storage.FileNode
@@ -80,12 +80,12 @@ func TestFileHandlers_Integration(t *testing.T) {
// Create all files // Create all files
for path, content := range files { for path, content := range files {
rr := h.makeRequest(t, http.MethodPost, baseURL+"/"+path, content, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/"+path, content, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
} }
// List all files // List all files
rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var fileNodes []storage.FileNode var fileNodes []storage.FileNode
@@ -116,11 +116,11 @@ func TestFileHandlers_Integration(t *testing.T) {
// Look up a file that exists in multiple locations // Look up a file that exists in multiple locations
filename := "readme.md" filename := "readme.md"
dupContent := "Another readme" dupContent := "Another readme"
rr := h.makeRequest(t, http.MethodPost, baseURL+"/projects/"+filename, dupContent, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/projects/"+filename, dupContent, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Search for the file // Search for the file
rr = h.makeRequest(t, http.MethodGet, baseURL+"/lookup?filename="+filename, nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, baseURL+"/lookup?filename="+filename, nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var response struct { var response struct {
@@ -131,7 +131,7 @@ func TestFileHandlers_Integration(t *testing.T) {
assert.Len(t, response.Paths, 2) assert.Len(t, response.Paths, 2)
// Search for non-existent file // Search for non-existent file
rr = h.makeRequest(t, http.MethodGet, baseURL+"/lookup?filename=nonexistent.md", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, baseURL+"/lookup?filename=nonexistent.md", nil, h.RegularTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
@@ -140,21 +140,21 @@ func TestFileHandlers_Integration(t *testing.T) {
content := "This file will be deleted" content := "This file will be deleted"
// Create file // Create file
rr := h.makeRequest(t, http.MethodPost, baseURL+"/"+filePath, content, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/"+filePath, content, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Delete file // Delete file
rr = h.makeRequest(t, http.MethodDelete, baseURL+"/"+filePath, nil, h.RegularSession) rr = h.makeRequest(t, http.MethodDelete, baseURL+"/"+filePath, nil, h.RegularTestUser)
require.Equal(t, http.StatusNoContent, rr.Code) require.Equal(t, http.StatusNoContent, rr.Code)
// Verify file is gone // Verify file is gone
rr = h.makeRequest(t, http.MethodGet, baseURL+"/"+filePath, nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, baseURL+"/"+filePath, nil, h.RegularTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
t.Run("last opened file", func(t *testing.T) { t.Run("last opened file", func(t *testing.T) {
// Initially should be empty // Initially should be empty
rr := h.makeRequest(t, http.MethodGet, baseURL+"/last", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, baseURL+"/last", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var response struct { var response struct {
@@ -170,11 +170,11 @@ func TestFileHandlers_Integration(t *testing.T) {
}{ }{
FilePath: "docs/readme.md", FilePath: "docs/readme.md",
} }
rr = h.makeRequest(t, http.MethodPut, baseURL+"/last", updateReq, h.RegularSession) rr = h.makeRequest(t, http.MethodPut, baseURL+"/last", updateReq, h.RegularTestUser)
require.Equal(t, http.StatusNoContent, rr.Code) require.Equal(t, http.StatusNoContent, rr.Code)
// Verify update // Verify update
rr = h.makeRequest(t, http.MethodGet, baseURL+"/last", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, baseURL+"/last", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
err = json.NewDecoder(rr.Body).Decode(&response) err = json.NewDecoder(rr.Body).Decode(&response)
@@ -183,7 +183,7 @@ func TestFileHandlers_Integration(t *testing.T) {
// Test invalid file path // Test invalid file path
updateReq.FilePath = "nonexistent.md" updateReq.FilePath = "nonexistent.md"
rr = h.makeRequest(t, http.MethodPut, baseURL+"/last", updateReq, h.RegularSession) rr = h.makeRequest(t, http.MethodPut, baseURL+"/last", updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
@@ -209,7 +209,7 @@ func TestFileHandlers_Integration(t *testing.T) {
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
// Test with wrong user's session // Test with wrong user's session
rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminSession) rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
} }
@@ -226,11 +226,11 @@ func TestFileHandlers_Integration(t *testing.T) {
for _, path := range maliciousPaths { for _, path := range maliciousPaths {
t.Run(path, func(t *testing.T) { t.Run(path, func(t *testing.T) {
// Try to read // Try to read
rr := h.makeRequest(t, http.MethodGet, baseURL+"/"+path, nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, baseURL+"/"+path, nil, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
// Try to write // Try to write
rr = h.makeRequest(t, http.MethodPost, baseURL+"/"+path, "malicious content", h.RegularSession) rr = h.makeRequest(t, http.MethodPost, baseURL+"/"+path, "malicious content", h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
} }

View File

@@ -22,7 +22,7 @@ func TestGitHandlers_Integration(t *testing.T) {
t.Run("git operations", func(t *testing.T) { t.Run("git operations", func(t *testing.T) {
// Setup: Create a workspace with Git enabled // Setup: Create a workspace with Git enabled
workspace := &models.Workspace{ workspace := &models.Workspace{
UserID: h.RegularUser.ID, UserID: h.RegularTestUser.session.UserID,
Name: "Git Test Workspace", Name: "Git Test Workspace",
GitEnabled: true, GitEnabled: true,
GitURL: "https://github.com/test/repo.git", GitURL: "https://github.com/test/repo.git",
@@ -32,7 +32,7 @@ func TestGitHandlers_Integration(t *testing.T) {
GitCommitMsgTemplate: "Update: {{message}}", GitCommitMsgTemplate: "Update: {{message}}",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
err := json.NewDecoder(rr.Body).Decode(workspace) err := json.NewDecoder(rr.Body).Decode(workspace)
@@ -50,7 +50,7 @@ func TestGitHandlers_Integration(t *testing.T) {
"message": commitMsg, "message": commitMsg,
} }
rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var response map[string]string var response map[string]string
@@ -70,7 +70,7 @@ func TestGitHandlers_Integration(t *testing.T) {
"message": "", "message": "",
} }
rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
assert.Equal(t, 0, h.MockGit.GetCommitCount(), "Commit should not be called") assert.Equal(t, 0, h.MockGit.GetCommitCount(), "Commit should not be called")
}) })
@@ -83,7 +83,7 @@ func TestGitHandlers_Integration(t *testing.T) {
"message": "Test message", "message": "Test message",
} }
rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularTestUser)
assert.Equal(t, http.StatusInternalServerError, rr.Code) assert.Equal(t, http.StatusInternalServerError, rr.Code)
h.MockGit.SetError(nil) // Reset error state h.MockGit.SetError(nil) // Reset error state
@@ -94,7 +94,7 @@ func TestGitHandlers_Integration(t *testing.T) {
h.MockGit.Reset() h.MockGit.Reset()
t.Run("successful pull", func(t *testing.T) { t.Run("successful pull", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodPost, baseURL+"/pull", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/pull", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var response map[string]string var response map[string]string
@@ -109,7 +109,7 @@ func TestGitHandlers_Integration(t *testing.T) {
h.MockGit.Reset() h.MockGit.Reset()
h.MockGit.SetError(fmt.Errorf("mock git error")) h.MockGit.SetError(fmt.Errorf("mock git error"))
rr := h.makeRequest(t, http.MethodPost, baseURL+"/pull", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, baseURL+"/pull", nil, h.RegularTestUser)
assert.Equal(t, http.StatusInternalServerError, rr.Code) assert.Equal(t, http.StatusInternalServerError, rr.Code)
h.MockGit.SetError(nil) // Reset error state h.MockGit.SetError(nil) // Reset error state
@@ -145,7 +145,7 @@ func TestGitHandlers_Integration(t *testing.T) {
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
// Test with wrong user's session // Test with wrong user's session
rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminSession) rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
} }
@@ -156,11 +156,11 @@ func TestGitHandlers_Integration(t *testing.T) {
// Create a workspace without Git enabled // Create a workspace without Git enabled
nonGitWorkspace := &models.Workspace{ nonGitWorkspace := &models.Workspace{
UserID: h.RegularUser.ID, UserID: h.RegularTestUser.session.UserID,
Name: "Non-Git Workspace", Name: "Non-Git Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", nonGitWorkspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", nonGitWorkspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
err := json.NewDecoder(rr.Body).Decode(nonGitWorkspace) err := json.NewDecoder(rr.Body).Decode(nonGitWorkspace)
@@ -170,11 +170,11 @@ func TestGitHandlers_Integration(t *testing.T) {
// Try to commit // Try to commit
commitMsg := map[string]string{"message": "test"} commitMsg := map[string]string{"message": "test"}
rr = h.makeRequest(t, http.MethodPost, nonGitBaseURL+"/commit", commitMsg, h.RegularSession) rr = h.makeRequest(t, http.MethodPost, nonGitBaseURL+"/commit", commitMsg, h.RegularTestUser)
assert.Equal(t, http.StatusInternalServerError, rr.Code) assert.Equal(t, http.StatusInternalServerError, rr.Code)
// Try to pull // Try to pull
rr = h.makeRequest(t, http.MethodPost, nonGitBaseURL+"/pull", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodPost, nonGitBaseURL+"/pull", nil, h.RegularTestUser)
assert.Equal(t, http.StatusInternalServerError, rr.Code) assert.Equal(t, http.StatusInternalServerError, rr.Code)
}) })
}) })

View File

@@ -31,14 +31,18 @@ type testHarness struct {
JWTManager auth.JWTManager JWTManager auth.JWTManager
SessionManager auth.SessionManager SessionManager auth.SessionManager
CookieManager auth.CookieManager CookieManager auth.CookieManager
AdminUser *models.User AdminTestUser *testUser
AdminSession *models.Session RegularTestUser *testUser
RegularUser *models.User
RegularSession *models.Session
TempDirectory string TempDirectory string
MockGit *MockGitClient MockGit *MockGitClient
} }
type testUser struct {
userModel *models.User
accessToken string
session *models.Session
}
// setupTestHarness creates a new test environment // setupTestHarness creates a new test environment
func setupTestHarness(t *testing.T) *testHarness { func setupTestHarness(t *testing.T) *testHarness {
t.Helper() t.Helper()
@@ -110,6 +114,7 @@ func setupTestHarness(t *testing.T) *testHarness {
Storage: storageSvc, Storage: storageSvc,
JWTManager: jwtSvc, JWTManager: jwtSvc,
SessionManager: sessionSvc, SessionManager: sessionSvc,
CookieService: cookieSvc,
} }
// Create server // Create server
@@ -127,13 +132,11 @@ func setupTestHarness(t *testing.T) *testHarness {
} }
// Create test users // Create test users
adminUser, adminSession := h.createTestUser(t, "admin@test.com", "admin123", models.RoleAdmin) adminTestUser := h.createTestUser(t, "admin@test.com", "admin123", models.RoleAdmin)
regularUser, regularSession := h.createTestUser(t, "user@test.com", "user123", models.RoleEditor) regularTestUser := h.createTestUser(t, "user@test.com", "user123", models.RoleEditor)
h.AdminUser = adminUser h.AdminTestUser = adminTestUser
h.AdminSession = adminSession h.RegularTestUser = regularTestUser
h.RegularUser = regularUser
h.RegularSession = regularSession
return h return h
} }
@@ -152,7 +155,7 @@ func (h *testHarness) teardown(t *testing.T) {
} }
// createTestUser creates a test user and returns the user and access token // createTestUser creates a test user and returns the user and access token
func (h *testHarness) createTestUser(t *testing.T, email, password string, role models.UserRole) (*models.User, *models.Session) { func (h *testHarness) createTestUser(t *testing.T, email, password string, role models.UserRole) *testUser {
t.Helper() t.Helper()
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
@@ -178,12 +181,16 @@ func (h *testHarness) createTestUser(t *testing.T, email, password string, role
t.Fatalf("Failed to initialize user workspace: %v", err) t.Fatalf("Failed to initialize user workspace: %v", err)
} }
session, _, err := h.SessionManager.CreateSession(user.ID, string(user.Role)) session, accessToken, err := h.SessionManager.CreateSession(user.ID, string(user.Role))
if err != nil { if err != nil {
t.Fatalf("Failed to create session: %v", err) t.Fatalf("Failed to create session: %v", err)
} }
return user, session return &testUser{
userModel: user,
accessToken: accessToken,
session: session,
}
} }
func (h *testHarness) newRequest(t *testing.T, method, path string, body interface{}) *http.Request { func (h *testHarness) newRequest(t *testing.T, method, path string, body interface{}) *http.Request {
@@ -217,59 +224,53 @@ func (h *testHarness) executeRequest(req *http.Request) *httptest.ResponseRecord
} }
// addAuthCookies adds authentication cookies to request // addAuthCookies adds authentication cookies to request
func (h *testHarness) addAuthCookies(t *testing.T, req *http.Request, session *models.Session, addCSRF bool) string { func (h *testHarness) addAuthCookies(t *testing.T, req *http.Request, testUser *testUser) {
t.Helper() t.Helper()
if session == nil { if testUser == nil || testUser.session == nil {
return "" return
} }
accessToken, err := h.JWTManager.GenerateAccessToken(session.UserID, "admin") req.AddCookie(h.CookieManager.GenerateAccessTokenCookie(testUser.accessToken))
if err != nil { req.AddCookie(h.CookieManager.GenerateRefreshTokenCookie(testUser.session.RefreshToken))
t.Fatalf("Failed to generate access token: %v", err) }
}
req.AddCookie(h.CookieManager.GenerateAccessTokenCookie(accessToken)) func (h *testHarness) addCSRFCookie(t *testing.T, req *http.Request) string {
req.AddCookie(h.CookieManager.GenerateRefreshTokenCookie(session.RefreshToken)) t.Helper()
if addCSRF {
csrfToken := "test-csrf-token" csrfToken := "test-csrf-token"
req.AddCookie(h.CookieManager.GenerateCSRFCookie(csrfToken)) req.AddCookie(h.CookieManager.GenerateCSRFCookie(csrfToken))
return csrfToken return csrfToken
}
return ""
} }
// makeRequest is the main helper for making JSON requests // makeRequest is the main helper for making JSON requests
func (h *testHarness) makeRequest(t *testing.T, method, path string, body interface{}, session *models.Session) *httptest.ResponseRecorder { func (h *testHarness) makeRequest(t *testing.T, method, path string, body interface{}, testUser *testUser) *httptest.ResponseRecorder {
t.Helper() t.Helper()
req := h.newRequest(t, method, path, body) req := h.newRequest(t, method, path, body)
h.addAuthCookies(t, req, testUser)
if session != nil {
needsCSRF := method != http.MethodGet && method != http.MethodHead && method != http.MethodOptions needsCSRF := method != http.MethodGet && method != http.MethodHead && method != http.MethodOptions
csrfToken := h.addAuthCookies(t, req, session, needsCSRF)
if needsCSRF { if needsCSRF {
csrfToken := h.addCSRFCookie(t, req)
req.Header.Set("X-CSRF-Token", csrfToken) req.Header.Set("X-CSRF-Token", csrfToken)
} }
}
return h.executeRequest(req) return h.executeRequest(req)
} }
// makeRequestRawWithHeaders adds support for custom headers with raw body // makeRequestRawWithHeaders adds support for custom headers with raw body
func (h *testHarness) makeRequestRaw(t *testing.T, method, path string, body io.Reader, session *models.Session) *httptest.ResponseRecorder { func (h *testHarness) makeRequestRaw(t *testing.T, method, path string, body io.Reader, testUser *testUser) *httptest.ResponseRecorder {
t.Helper() t.Helper()
req := h.newRequestRaw(t, method, path, body) req := h.newRequestRaw(t, method, path, body)
h.addAuthCookies(t, req, testUser)
if session != nil {
needsCSRF := method != http.MethodGet && method != http.MethodHead && method != http.MethodOptions needsCSRF := method != http.MethodGet && method != http.MethodHead && method != http.MethodOptions
csrfToken := h.addAuthCookies(t, req, session, needsCSRF)
if needsCSRF { if needsCSRF {
csrfToken := h.addCSRFCookie(t, req)
req.Header.Set("X-CSRF-Token", csrfToken) req.Header.Set("X-CSRF-Token", csrfToken)
} }
}
return h.executeRequest(req) return h.executeRequest(req)
} }

View File

@@ -18,22 +18,22 @@ func TestUserHandlers_Integration(t *testing.T) {
h := setupTestHarness(t) h := setupTestHarness(t)
defer h.teardown(t) defer h.teardown(t)
currentEmail := h.RegularUser.Email currentEmail := h.RegularTestUser.userModel.Email
currentPassword := "user123" currentPassword := "user123"
t.Run("get current user", func(t *testing.T) { t.Run("get current user", func(t *testing.T) {
t.Run("successful get", func(t *testing.T) { t.Run("successful get", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var user models.User var user models.User
err := json.NewDecoder(rr.Body).Decode(&user) err := json.NewDecoder(rr.Body).Decode(&user)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, h.RegularUser.ID, user.ID) assert.Equal(t, h.RegularTestUser.userModel.ID, user.ID)
assert.Equal(t, h.RegularUser.Email, user.Email) assert.Equal(t, h.RegularTestUser.userModel.Email, user.Email)
assert.Equal(t, h.RegularUser.DisplayName, user.DisplayName) assert.Equal(t, h.RegularTestUser.userModel.DisplayName, user.DisplayName)
assert.Equal(t, h.RegularUser.Role, user.Role) assert.Equal(t, h.RegularTestUser.userModel.Role, user.Role)
assert.Empty(t, user.PasswordHash, "Password hash should not be included in response") assert.Empty(t, user.PasswordHash, "Password hash should not be included in response")
}) })
@@ -49,7 +49,7 @@ func TestUserHandlers_Integration(t *testing.T) {
DisplayName: "Updated Name", DisplayName: "Updated Name",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var user models.User var user models.User
@@ -64,7 +64,7 @@ func TestUserHandlers_Integration(t *testing.T) {
CurrentPassword: currentPassword, CurrentPassword: currentPassword,
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var user models.User var user models.User
@@ -80,7 +80,7 @@ func TestUserHandlers_Integration(t *testing.T) {
Email: "anotheremail@test.com", Email: "anotheremail@test.com",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
@@ -90,7 +90,7 @@ func TestUserHandlers_Integration(t *testing.T) {
CurrentPassword: "wrongpassword", CurrentPassword: "wrongpassword",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -100,7 +100,7 @@ func TestUserHandlers_Integration(t *testing.T) {
NewPassword: "newpassword123", NewPassword: "newpassword123",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Verify can login with new password // Verify can login with new password
@@ -120,7 +120,7 @@ func TestUserHandlers_Integration(t *testing.T) {
NewPassword: "newpass123", NewPassword: "newpass123",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
@@ -130,7 +130,7 @@ func TestUserHandlers_Integration(t *testing.T) {
NewPassword: "newpass123", NewPassword: "newpass123",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -140,68 +140,40 @@ func TestUserHandlers_Integration(t *testing.T) {
NewPassword: "short", NewPassword: "short",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
t.Run("duplicate email", func(t *testing.T) { t.Run("duplicate email", func(t *testing.T) {
updateReq := handlers.UpdateProfileRequest{ updateReq := handlers.UpdateProfileRequest{
Email: h.AdminUser.Email, Email: h.AdminTestUser.userModel.Email,
CurrentPassword: currentPassword, CurrentPassword: currentPassword,
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularTestUser)
assert.Equal(t, http.StatusConflict, rr.Code) assert.Equal(t, http.StatusConflict, rr.Code)
}) })
}) })
t.Run("delete account", func(t *testing.T) { t.Run("delete account", func(t *testing.T) {
// Create a new user that we can delete
createReq := handlers.CreateUserRequest{
Email: "todelete@test.com",
DisplayName: "To Delete",
Password: "password123",
Role: models.RoleEditor,
}
rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession) deleteUserPassword := "password123"
require.Equal(t, http.StatusOK, rr.Code) testDeleteUser := h.createTestUser(t, "todelete@test.com", deleteUserPassword, models.RoleEditor)
var newUser models.User
err := json.NewDecoder(rr.Body).Decode(&newUser)
require.NoError(t, err)
// Get session for new user
loginReq := handlers.LoginRequest{
Email: createReq.Email,
Password: createReq.Password,
}
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, nil)
require.Equal(t, http.StatusOK, rr.Code)
var loginResp handlers.LoginResponse
err = json.NewDecoder(rr.Body).Decode(&loginResp)
require.NoError(t, err)
// Create a session struct for the new user
userSession := &models.Session{
ID: loginResp.SessionID,
UserID: newUser.ID,
RefreshToken: "",
ExpiresAt: loginResp.ExpiresAt,
}
t.Run("successful delete", func(t *testing.T) { t.Run("successful delete", func(t *testing.T) {
deleteReq := handlers.DeleteAccountRequest{ deleteReq := handlers.DeleteAccountRequest{
Password: createReq.Password, Password: deleteUserPassword,
} }
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, userSession) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, testDeleteUser)
require.Equal(t, http.StatusNoContent, rr.Code) require.Equal(t, http.StatusNoContent, rr.Code)
// Verify user is deleted // Verify user is deleted
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, nil) loginReq := handlers.LoginRequest{
Email: testDeleteUser.userModel.Email,
Password: deleteUserPassword,
}
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, testDeleteUser)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -210,7 +182,7 @@ func TestUserHandlers_Integration(t *testing.T) {
Password: "wrongpassword", Password: "wrongpassword",
} }
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, h.RegularSession) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, h.RegularTestUser)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -219,7 +191,7 @@ func TestUserHandlers_Integration(t *testing.T) {
Password: "admin123", // Admin password from test harness Password: "admin123", // Admin password from test harness
} }
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, h.AdminSession) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, h.AdminTestUser)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
}) })

View File

@@ -20,7 +20,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
t.Run("list workspaces", func(t *testing.T) { t.Run("list workspaces", func(t *testing.T) {
t.Run("successful list", func(t *testing.T) { t.Run("successful list", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var workspaces []*models.Workspace var workspaces []*models.Workspace
@@ -41,14 +41,14 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
Name: "Test Workspace", Name: "Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var created models.Workspace var created models.Workspace
err := json.NewDecoder(rr.Body).Decode(&created) err := json.NewDecoder(rr.Body).Decode(&created)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, workspace.Name, created.Name) assert.Equal(t, workspace.Name, created.Name)
assert.Equal(t, h.RegularUser.ID, created.UserID) assert.Equal(t, h.RegularTestUser.session.UserID, created.UserID)
assert.NotZero(t, created.ID) assert.NotZero(t, created.ID)
}) })
@@ -64,7 +64,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
GitCommitEmail: "test@example.com", GitCommitEmail: "test@example.com",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var created models.Workspace var created models.Workspace
@@ -86,7 +86,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
// Missing required Git settings // Missing required Git settings
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
}) })
@@ -95,7 +95,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
workspace := &models.Workspace{ workspace := &models.Workspace{
Name: "Test Workspace Operations", Name: "Test Workspace Operations",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
err := json.NewDecoder(rr.Body).Decode(workspace) err := json.NewDecoder(rr.Body).Decode(workspace)
require.NoError(t, err) require.NoError(t, err)
@@ -105,7 +105,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
t.Run("get workspace", func(t *testing.T) { t.Run("get workspace", func(t *testing.T) {
t.Run("successful get", func(t *testing.T) { t.Run("successful get", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var got models.Workspace var got models.Workspace
@@ -116,13 +116,13 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
}) })
t.Run("nonexistent workspace", func(t *testing.T) { t.Run("nonexistent workspace", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/nonexistent", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/nonexistent", nil, h.RegularTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
t.Run("unauthorized access", func(t *testing.T) { t.Run("unauthorized access", func(t *testing.T) {
// Try accessing with another user's token // Try accessing with another user's token
rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.AdminSession) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.AdminTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
}) })
@@ -131,7 +131,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
t.Run("update name", func(t *testing.T) { t.Run("update name", func(t *testing.T) {
workspace.Name = "Updated Workspace" workspace.Name = "Updated Workspace"
rr := h.makeRequest(t, http.MethodPut, baseURL, workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, baseURL, workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var updated models.Workspace var updated models.Workspace
@@ -152,7 +152,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
ShowHiddenFiles: true, ShowHiddenFiles: true,
} }
rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var updated models.Workspace var updated models.Workspace
@@ -176,7 +176,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
GitCommitEmail: "test@example.com", GitCommitEmail: "test@example.com",
} }
rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var updated models.Workspace var updated models.Workspace
@@ -200,14 +200,14 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
// Missing required Git settings // Missing required Git settings
} }
rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
}) })
t.Run("last workspace", func(t *testing.T) { t.Run("last workspace", func(t *testing.T) {
t.Run("get last workspace", func(t *testing.T) { t.Run("get last workspace", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/last", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/last", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var response struct { var response struct {
@@ -225,11 +225,11 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
WorkspaceName: workspace.Name, WorkspaceName: workspace.Name,
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/workspaces/last", req, h.RegularSession) rr := h.makeRequest(t, http.MethodPut, "/api/v1/workspaces/last", req, h.RegularTestUser)
require.Equal(t, http.StatusNoContent, rr.Code) require.Equal(t, http.StatusNoContent, rr.Code)
// Verify the update // Verify the update
rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/last", nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/last", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var response struct { var response struct {
@@ -243,7 +243,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
t.Run("delete workspace", func(t *testing.T) { t.Run("delete workspace", func(t *testing.T) {
// Get current workspaces to know how many we have // Get current workspaces to know how many we have
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, h.RegularSession) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var existingWorkspaces []*models.Workspace var existingWorkspaces []*models.Workspace
@@ -254,13 +254,13 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
newWorkspace := &models.Workspace{ newWorkspace := &models.Workspace{
Name: "Workspace To Delete", Name: "Workspace To Delete",
} }
rr = h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", newWorkspace, h.RegularSession) rr = h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", newWorkspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
err = json.NewDecoder(rr.Body).Decode(newWorkspace) err = json.NewDecoder(rr.Body).Decode(newWorkspace)
require.NoError(t, err) require.NoError(t, err)
t.Run("successful delete", func(t *testing.T) { t.Run("successful delete", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(newWorkspace.Name), nil, h.RegularSession) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(newWorkspace.Name), nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var response struct { var response struct {
@@ -271,7 +271,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
assert.NotEmpty(t, response.NextWorkspaceName) assert.NotEmpty(t, response.NextWorkspaceName)
// Verify workspace is deleted // Verify workspace is deleted
rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/"+url.PathEscape(newWorkspace.Name), nil, h.RegularSession) rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/"+url.PathEscape(newWorkspace.Name), nil, h.RegularTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
@@ -279,13 +279,13 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
// Delete all but one workspace // Delete all but one workspace
for i := 0; i < len(existingWorkspaces)-1; i++ { for i := 0; i < len(existingWorkspaces)-1; i++ {
ws := existingWorkspaces[i] ws := existingWorkspaces[i]
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(ws.Name), nil, h.RegularSession) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(ws.Name), nil, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
} }
// Try to delete the last remaining workspace // Try to delete the last remaining workspace
lastWs := existingWorkspaces[len(existingWorkspaces)-1] lastWs := existingWorkspaces[len(existingWorkspaces)-1]
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(lastWs.Name), nil, h.RegularSession) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(lastWs.Name), nil, h.RegularTestUser)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
@@ -294,11 +294,11 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
workspace := &models.Workspace{ workspace := &models.Workspace{
Name: "Unauthorized Delete Test", Name: "Unauthorized Delete Test",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularTestUser)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Try to delete with wrong user's token // Try to delete with wrong user's token
rr = h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(workspace.Name), nil, h.AdminSession) rr = h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(workspace.Name), nil, h.AdminTestUser)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
}) })