Update handler integration tests

This commit is contained in:
2024-12-07 23:09:57 +01:00
parent ad4af2f82d
commit 5633406f5c
7 changed files with 427 additions and 244 deletions

View File

@@ -34,8 +34,8 @@ 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 token // Test with admin session
rr := h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.AdminToken, nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.AdminSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var users []*models.User var users []*models.User
@@ -47,12 +47,12 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.True(t, containsUser(users, h.AdminUser), "Admin user not found in users list") assert.True(t, containsUser(users, h.AdminUser), "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.RegularUser), "Regular user not found in users list")
// Test with non-admin token // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, h.RegularSession, nil)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
// Test without token // Test without session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, "", nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users", nil, nil, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -64,8 +64,8 @@ func TestAdminHandlers_Integration(t *testing.T) {
Role: models.RoleEditor, Role: models.RoleEditor,
} }
// Test with admin token // Test with admin session
rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession, nil)
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.AdminToken, nil) rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession, nil)
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,19 +85,19 @@ 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.AdminToken, nil) rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", invalidReq, h.AdminSession, nil)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
// Test with non-admin token // Test with non-admin session
rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.RegularToken, nil) rr = h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.RegularSession, nil)
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.RegularUser.ID)
// Test with admin token // Test with admin session
rr := h.makeRequest(t, http.MethodGet, path, nil, h.AdminToken, nil) rr := h.makeRequest(t, http.MethodGet, path, nil, h.AdminSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var user models.User var user models.User
@@ -106,11 +106,11 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.Equal(t, h.RegularUser.ID, user.ID) assert.Equal(t, h.RegularUser.ID, user.ID)
// Test non-existent user // Test non-existent user
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users/999999", nil, h.AdminToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/users/999999", nil, h.AdminSession, nil)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
// Test with non-admin token // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, path, nil, h.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, path, nil, h.RegularSession, nil)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
@@ -121,8 +121,8 @@ func TestAdminHandlers_Integration(t *testing.T) {
Role: models.RoleViewer, Role: models.RoleViewer,
} }
// Test with admin token // Test with admin session
rr := h.makeRequest(t, http.MethodPut, path, updateReq, h.AdminToken, nil) rr := h.makeRequest(t, http.MethodPut, path, updateReq, h.AdminSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var updatedUser models.User var updatedUser models.User
@@ -131,8 +131,8 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.Equal(t, updateReq.DisplayName, updatedUser.DisplayName) assert.Equal(t, updateReq.DisplayName, updatedUser.DisplayName)
assert.Equal(t, updateReq.Role, updatedUser.Role) assert.Equal(t, updateReq.Role, updatedUser.Role)
// Test with non-admin token // Test with non-admin session
rr = h.makeRequest(t, http.MethodPut, path, updateReq, h.RegularToken, nil) rr = h.makeRequest(t, http.MethodPut, path, updateReq, h.RegularSession, nil)
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.AdminToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var createdUser models.User var createdUser models.User
@@ -156,19 +156,19 @@ func TestAdminHandlers_Integration(t *testing.T) {
// 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.AdminUser.ID)
rr = h.makeRequest(t, http.MethodDelete, adminPath, nil, h.AdminToken, nil) rr = h.makeRequest(t, http.MethodDelete, adminPath, nil, h.AdminSession, nil)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
// Test with admin token // Test with admin session
rr = h.makeRequest(t, http.MethodDelete, path, nil, h.AdminToken, nil) rr = h.makeRequest(t, http.MethodDelete, path, nil, h.AdminSession, nil)
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.AdminToken, nil) rr = h.makeRequest(t, http.MethodGet, path, nil, h.AdminSession, nil)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
// Test with non-admin token // Test with non-admin session
rr = h.makeRequest(t, http.MethodDelete, path, nil, h.RegularToken, nil) rr = h.makeRequest(t, http.MethodDelete, path, nil, h.RegularSession, nil)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
}) })
@@ -181,11 +181,11 @@ func TestAdminHandlers_Integration(t *testing.T) {
Name: "Test Workspace", Name: "Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Test with admin token // Test with admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.AdminToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.AdminSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var workspaces []*handlers.WorkspaceStats var workspaces []*handlers.WorkspaceStats
@@ -206,8 +206,8 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.GreaterOrEqual(t, ws.TotalSize, int64(0)) assert.GreaterOrEqual(t, ws.TotalSize, int64(0))
} }
// Test with non-admin token // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/workspaces", nil, h.RegularSession, nil)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
}) })
@@ -218,11 +218,11 @@ func TestAdminHandlers_Integration(t *testing.T) {
UserID: h.RegularUser.ID, UserID: h.RegularUser.ID,
Name: "Stats Test Workspace", Name: "Stats Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Test with admin token // Test with admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.AdminToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.AdminSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var stats handlers.SystemStats var stats handlers.SystemStats
@@ -236,8 +236,8 @@ func TestAdminHandlers_Integration(t *testing.T) {
assert.GreaterOrEqual(t, stats.TotalFiles, 0) assert.GreaterOrEqual(t, stats.TotalFiles, 0)
assert.GreaterOrEqual(t, stats.TotalSize, int64(0)) assert.GreaterOrEqual(t, stats.TotalSize, int64(0))
// Test with non-admin token // Test with non-admin session
rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/admin/stats", nil, h.RegularSession, nil)
assert.Equal(t, http.StatusForbidden, rr.Code) assert.Equal(t, http.StatusForbidden, rr.Code)
}) })
} }

View File

@@ -4,8 +4,12 @@ package handlers_test
import ( import (
"encoding/json" "encoding/json"
"io"
"net/http" "net/http"
"net/http/httptest"
"strings"
"testing" "testing"
"time"
"novamd/internal/handlers" "novamd/internal/handlers"
"novamd/internal/models" "novamd/internal/models"
@@ -25,40 +29,58 @@ func TestAuthHandlers_Integration(t *testing.T) {
Password: "admin123", Password: "admin123",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, "", nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, nil, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
// Verify all required cookies are present with correct attributes
cookies := rr.Result().Cookies()
var foundAccessToken, foundRefreshToken, foundCSRF bool
for _, cookie := range cookies {
switch cookie.Name {
case "access_token":
foundAccessToken = true
assert.True(t, cookie.HttpOnly, "access_token cookie must be HttpOnly")
assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite)
assert.Equal(t, 900, cookie.MaxAge) // 15 minutes
case "refresh_token":
foundRefreshToken = true
assert.True(t, cookie.HttpOnly, "refresh_token cookie must be HttpOnly")
assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite)
assert.Equal(t, 604800, cookie.MaxAge) // 7 days
case "csrf_token":
foundCSRF = true
assert.False(t, cookie.HttpOnly, "csrf_token cookie must not be HttpOnly")
assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite)
assert.Equal(t, 900, cookie.MaxAge) // 15 minutes
}
}
assert.True(t, foundAccessToken, "access_token cookie not found")
assert.True(t, foundRefreshToken, "refresh_token cookie not found")
assert.True(t, foundCSRF, "csrf_token cookie not found")
// Verify CSRF token is in both cookie and header, and they match
var csrfCookie *http.Cookie
for _, cookie := range rr.Result().Cookies() {
if cookie.Name == "csrf_token" {
csrfCookie = cookie
break
}
}
require.NotNil(t, csrfCookie, "csrf_token cookie not found")
csrfHeader := rr.Header().Get("X-CSRF-Token")
assert.Equal(t, csrfCookie.Value, csrfHeader)
// Verify response body
var resp handlers.LoginResponse var resp handlers.LoginResponse
err := json.NewDecoder(rr.Body).Decode(&resp) err := json.NewDecoder(rr.Body).Decode(&resp)
require.NoError(t, err) require.NoError(t, err)
assert.NotEmpty(t, resp.SessionID)
assert.NotEmpty(t, resp.AccessToken) assert.False(t, resp.ExpiresAt.IsZero())
assert.NotEmpty(t, resp.RefreshToken)
assert.NotNil(t, resp.User) assert.NotNil(t, resp.User)
assert.Equal(t, loginReq.Email, resp.User.Email) assert.Equal(t, loginReq.Email, resp.User.Email)
assert.Equal(t, models.RoleAdmin, resp.User.Role) assert.Equal(t, models.RoleAdmin, resp.User.Role)
}) })
t.Run("successful login - regular user", func(t *testing.T) {
loginReq := handlers.LoginRequest{
Email: "user@test.com",
Password: "user123",
}
rr := h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, "", nil)
require.Equal(t, http.StatusOK, rr.Code)
var resp handlers.LoginResponse
err := json.NewDecoder(rr.Body).Decode(&resp)
require.NoError(t, err)
assert.NotEmpty(t, resp.AccessToken)
assert.NotEmpty(t, resp.RefreshToken)
assert.NotNil(t, resp.User)
assert.Equal(t, loginReq.Email, resp.User.Email)
assert.Equal(t, models.RoleEditor, resp.User.Role)
})
t.Run("login failures", func(t *testing.T) { t.Run("login failures", func(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
@@ -97,12 +119,26 @@ func TestAuthHandlers_Integration(t *testing.T) {
}, },
wantCode: http.StatusBadRequest, wantCode: http.StatusBadRequest,
}, },
{
name: "malformed JSON",
request: handlers.LoginRequest{}, // Will be overridden with bad JSON
wantCode: http.StatusBadRequest,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
rr := h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", tt.request, "", nil) var rr *httptest.ResponseRecorder
if tt.name == "malformed JSON" {
// Need lower level helper to send malformed JSON
req := h.newRequest(t, http.MethodPost, "/api/v1/auth/login", nil)
req.Body = io.NopCloser(strings.NewReader("{bad json"))
rr = h.executeRequest(req)
} else {
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", tt.request, nil, nil)
}
assert.Equal(t, tt.wantCode, rr.Code) assert.Equal(t, tt.wantCode, rr.Code)
assert.Empty(t, rr.Result().Cookies(), "failed login should not set cookies")
}) })
} }
}) })
@@ -110,58 +146,76 @@ func TestAuthHandlers_Integration(t *testing.T) {
t.Run("refresh token", func(t *testing.T) { t.Run("refresh token", func(t *testing.T) {
t.Run("successful token refresh", func(t *testing.T) { t.Run("successful token refresh", func(t *testing.T) {
// First login to get refresh token // Need lower level helpers for precise cookie control
loginReq := handlers.LoginRequest{ req := h.newRequest(t, http.MethodPost, "/api/v1/auth/refresh", nil)
Email: "user@test.com", h.addAuthCookies(t, req, h.RegularSession, true) // Adds both tokens
Password: "user123", rr := h.executeRequest(req)
}
rr := h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, "", nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var loginResp handlers.LoginResponse // Verify new cookies
err := json.NewDecoder(rr.Body).Decode(&loginResp) cookies := rr.Result().Cookies()
require.NoError(t, err) var foundAccessToken, foundCSRF bool
for _, cookie := range cookies {
// Now try to refresh the token switch cookie.Name {
refreshReq := handlers.RefreshRequest{ case "access_token":
RefreshToken: loginResp.RefreshToken, foundAccessToken = true
assert.Equal(t, 900, cookie.MaxAge)
case "csrf_token":
foundCSRF = true
assert.Equal(t, 900, cookie.MaxAge)
case "refresh_token":
t.Error("refresh token should not be renewed")
} }
}
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/refresh", refreshReq, "", nil) assert.True(t, foundAccessToken, "new access_token cookie not found")
require.Equal(t, http.StatusOK, rr.Code) assert.True(t, foundCSRF, "new csrf_token cookie not found")
var refreshResp handlers.RefreshResponse
err = json.NewDecoder(rr.Body).Decode(&refreshResp)
require.NoError(t, err)
assert.NotEmpty(t, refreshResp.AccessToken)
}) })
t.Run("refresh failures", func(t *testing.T) { t.Run("refresh token edge cases", func(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
request handlers.RefreshRequest setup func(*http.Request)
wantCode int wantCode int
}{ }{
{ {
name: "invalid refresh token", name: "missing refresh token cookie",
request: handlers.RefreshRequest{ setup: func(req *http.Request) {
RefreshToken: "invalid-token", // Only add access token
token, _ := h.JWTManager.GenerateAccessToken(h.RegularSession.UserID, "admin")
req.AddCookie(h.CookieManager.GenerateAccessTokenCookie(token))
},
wantCode: http.StatusBadRequest,
},
{
name: "expired refresh token",
setup: func(req *http.Request) {
expiredSession := &models.Session{
ID: "expired",
UserID: h.RegularUser.ID,
RefreshToken: "expired-token",
ExpiresAt: time.Now().Add(-1 * time.Hour),
}
h.addAuthCookies(t, req, expiredSession, true)
}, },
wantCode: http.StatusUnauthorized, wantCode: http.StatusUnauthorized,
}, },
{ {
name: "empty refresh token", name: "invalid refresh token format",
request: handlers.RefreshRequest{ setup: func(req *http.Request) {
RefreshToken: "", req.AddCookie(&http.Cookie{
Name: "refresh_token",
Value: "invalid-format",
})
}, },
wantCode: http.StatusBadRequest, wantCode: http.StatusUnauthorized,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
rr := h.makeRequest(t, http.MethodPost, "/api/v1/auth/refresh", tt.request, "", nil) req := h.newRequest(t, http.MethodPost, "/api/v1/auth/refresh", nil)
tt.setup(req)
rr := h.executeRequest(req)
assert.Equal(t, tt.wantCode, rr.Code) assert.Equal(t, tt.wantCode, rr.Code)
}) })
} }
@@ -170,63 +224,136 @@ func TestAuthHandlers_Integration(t *testing.T) {
t.Run("logout", func(t *testing.T) { t.Run("logout", func(t *testing.T) {
t.Run("successful logout", func(t *testing.T) { t.Run("successful logout", func(t *testing.T) {
// First login to get session // Need CSRF token for POST request
loginReq := handlers.LoginRequest{ req := h.newRequest(t, http.MethodPost, "/api/v1/auth/logout", nil)
Email: "user@test.com", csrfToken := h.addAuthCookies(t, req, h.RegularSession, true)
Password: "user123", req.Header.Set("X-CSRF-Token", csrfToken)
} rr := h.executeRequest(req)
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)
// Now logout using session ID from login response
headers := map[string]string{
"X-Session-ID": loginResp.Session.ID,
}
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/logout", nil, loginResp.AccessToken, headers)
require.Equal(t, http.StatusNoContent, rr.Code) require.Equal(t, http.StatusNoContent, rr.Code)
// Try to use the refresh token - should fail // Verify cookies are properly invalidated
refreshReq := handlers.RefreshRequest{ for _, cookie := range rr.Result().Cookies() {
RefreshToken: loginResp.RefreshToken, assert.True(t, cookie.MaxAge < 0, "cookie should be invalidated")
assert.True(t, cookie.Expires.Before(time.Now()), "cookie should be expired")
} }
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/refresh", refreshReq, "", nil) // Verify session is actually invalidated
rr = h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularSession, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
t.Run("logout without session ID", func(t *testing.T) { t.Run("logout edge cases", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodPost, "/api/v1/auth/logout", nil, h.RegularToken, nil) tests := []struct {
assert.Equal(t, http.StatusBadRequest, rr.Code) name string
setup func(*http.Request)
wantCode int
}{
{
name: "missing CSRF token",
setup: func(req *http.Request) {
h.addAuthCookies(t, req, h.RegularSession, true)
// Deliberately not setting X-CSRF-Token header
},
wantCode: http.StatusForbidden,
},
{
name: "mismatched CSRF token",
setup: func(req *http.Request) {
h.addAuthCookies(t, req, h.RegularSession, true)
req.Header.Set("X-CSRF-Token", "wrong-token")
},
wantCode: http.StatusForbidden,
},
{
name: "missing auth cookies",
setup: func(req *http.Request) {
// No setup - testing completely unauthenticated request
},
wantCode: http.StatusUnauthorized,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := h.newRequest(t, http.MethodPost, "/api/v1/auth/logout", nil)
tt.setup(req)
rr := h.executeRequest(req)
assert.Equal(t, tt.wantCode, rr.Code)
})
}
}) })
}) })
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularSession, nil)
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.RegularUser.Email, user.Email) assert.Equal(t, h.RegularUser.Email, user.Email)
assert.Equal(t, h.RegularUser.Role, user.Role)
}) })
t.Run("get current user without token", func(t *testing.T) { t.Run("auth edge cases", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, "", nil) tests := []struct {
assert.Equal(t, http.StatusUnauthorized, rr.Code) name string
setup func(*http.Request)
wantCode int
}{
{
name: "missing auth cookie",
setup: func(req *http.Request) {
// No setup - testing unauthenticated request
},
wantCode: http.StatusUnauthorized,
},
{
name: "invalid session ID",
setup: func(req *http.Request) {
invalidSession := &models.Session{
ID: "invalid",
UserID: 999,
RefreshToken: "invalid",
ExpiresAt: time.Now().Add(time.Hour),
}
h.addAuthCookies(t, req, invalidSession, false)
},
wantCode: http.StatusUnauthorized,
},
{
name: "expired session",
setup: func(req *http.Request) {
expiredSession := &models.Session{
ID: "expired",
UserID: h.RegularUser.ID,
RefreshToken: "expired-token",
ExpiresAt: time.Now().Add(-1 * time.Hour),
}
h.addAuthCookies(t, req, expiredSession, false)
},
wantCode: http.StatusUnauthorized,
},
{
name: "malformed access token",
setup: func(req *http.Request) {
req.AddCookie(&http.Cookie{
Name: "access_token",
Value: "malformed-token",
}) })
},
wantCode: http.StatusUnauthorized,
},
}
t.Run("get current user with invalid token", func(t *testing.T) { for _, tt := range tests {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, "invalid-token", nil) t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, http.StatusUnauthorized, rr.Code) req := h.newRequest(t, http.MethodGet, "/api/v1/auth/me", nil)
tt.setup(req)
rr := h.executeRequest(req)
assert.Equal(t, tt.wantCode, rr.Code)
})
}
}) })
}) })
} }

View File

@@ -27,7 +27,7 @@ func TestFileHandlers_Integration(t *testing.T) {
UserID: h.RegularUser.ID, UserID: h.RegularUser.ID,
Name: "File Test Workspace", Name: "File Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequestRaw(t, http.MethodPost, baseURL+"/"+filePath, strings.NewReader(content), h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, baseURL+"/"+filePath, nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/"+path, content, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/projects/"+filename, dupContent, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, baseURL+"/lookup?filename="+filename, nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, baseURL+"/lookup?filename=nonexistent.md", nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/"+filePath, content, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodDelete, baseURL+"/"+filePath, nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, baseURL+"/"+filePath, nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, baseURL+"/last", nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodPut, baseURL+"/last", updateReq, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, baseURL+"/last", nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodPut, baseURL+"/last", updateReq, h.RegularSession, nil)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
@@ -204,12 +204,12 @@ func TestFileHandlers_Integration(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
// Test without token // Test without session
rr := h.makeRequest(t, tc.method, tc.path, tc.body, "", nil) rr := h.makeRequest(t, tc.method, tc.path, tc.body, nil, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
// Test with wrong user's token // Test with wrong user's session
rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminToken, nil) rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, baseURL+"/"+path, nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodPost, baseURL+"/"+path, "malicious content", h.RegularSession, nil)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
} }

View File

@@ -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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/commit", requestBody, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/pull", nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, baseURL+"/pull", nil, h.RegularSession, nil)
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
@@ -140,12 +140,12 @@ func TestGitHandlers_Integration(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
// Test without token // Test without session
rr := h.makeRequest(t, tc.method, tc.path, tc.body, "", nil) rr := h.makeRequest(t, tc.method, tc.path, tc.body, nil, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
// Test with wrong user's token // Test with wrong user's session
rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminToken, nil) rr = h.makeRequest(t, tc.method, tc.path, tc.body, h.AdminSession, nil)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
} }
@@ -160,7 +160,7 @@ func TestGitHandlers_Integration(t *testing.T) {
Name: "Non-Git Workspace", Name: "Non-Git Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", nonGitWorkspace, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", nonGitWorkspace, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodPost, nonGitBaseURL+"/commit", commitMsg, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodPost, nonGitBaseURL+"/pull", nil, h.RegularSession, nil)
assert.Equal(t, http.StatusInternalServerError, rr.Code) assert.Equal(t, http.StatusInternalServerError, rr.Code)
}) })
}) })

View File

@@ -6,6 +6,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"io" "io"
"net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
"testing" "testing"
@@ -29,10 +30,11 @@ type testHarness struct {
Storage storage.Manager Storage storage.Manager
JWTManager auth.JWTManager JWTManager auth.JWTManager
SessionManager auth.SessionManager SessionManager auth.SessionManager
CookieManager auth.CookieManager
AdminUser *models.User AdminUser *models.User
AdminToken string AdminSession *models.Session
RegularUser *models.User RegularUser *models.User
RegularToken string RegularSession *models.Session
TempDirectory string TempDirectory string
MockGit *MockGitClient MockGit *MockGitClient
} }
@@ -86,6 +88,9 @@ func setupTestHarness(t *testing.T) *testHarness {
// Initialize session service // Initialize session service
sessionSvc := auth.NewSessionService(database, jwtSvc) sessionSvc := auth.NewSessionService(database, jwtSvc)
// Initialize cookie service
cookieSvc := auth.NewCookieService(true, "localhost")
// Create test config // Create test config
testConfig := &app.Config{ testConfig := &app.Config{
DBPath: ":memory:", DBPath: ":memory:",
@@ -116,18 +121,19 @@ func setupTestHarness(t *testing.T) *testHarness {
Storage: storageSvc, Storage: storageSvc,
JWTManager: jwtSvc, JWTManager: jwtSvc,
SessionManager: sessionSvc, SessionManager: sessionSvc,
CookieManager: cookieSvc,
TempDirectory: tempDir, TempDirectory: tempDir,
MockGit: mockGit, MockGit: mockGit,
} }
// Create test users // Create test users
adminUser, adminToken := h.createTestUser(t, "admin@test.com", "admin123", models.RoleAdmin) adminUser, adminSession := h.createTestUser(t, "admin@test.com", "admin123", models.RoleAdmin)
regularUser, regularToken := h.createTestUser(t, "user@test.com", "user123", models.RoleEditor) regularUser, regularSession := h.createTestUser(t, "user@test.com", "user123", models.RoleEditor)
h.AdminUser = adminUser h.AdminUser = adminUser
h.AdminToken = adminToken h.AdminSession = adminSession
h.RegularUser = regularUser h.RegularUser = regularUser
h.RegularToken = regularToken h.RegularSession = regularSession
return h return h
} }
@@ -146,7 +152,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, string) { func (h *testHarness) createTestUser(t *testing.T, email, password string, role models.UserRole) (*models.User, *models.Session) {
t.Helper() t.Helper()
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
@@ -172,25 +178,19 @@ 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, accessToken, err := h.SessionManager.CreateSession(user.ID, string(user.Role)) session, _, 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)
} }
if session == nil || accessToken == "" { return user, session
t.Fatal("Failed to get valid session or token")
}
return user, accessToken
} }
// makeRequest is a helper function to make HTTP requests in tests func (h *testHarness) newRequest(t *testing.T, method, path string, body interface{}) *http.Request {
func (h *testHarness) makeRequest(t *testing.T, method, path string, body interface{}, token string, headers map[string]string) *httptest.ResponseRecorder {
t.Helper() t.Helper()
var reqBody []byte var reqBody []byte
var err error var err error
if body != nil { if body != nil {
reqBody, err = json.Marshal(body) reqBody, err = json.Marshal(body)
if err != nil { if err != nil {
@@ -199,38 +199,87 @@ func (h *testHarness) makeRequest(t *testing.T, method, path string, body interf
} }
req := httptest.NewRequest(method, path, bytes.NewBuffer(reqBody)) req := httptest.NewRequest(method, path, bytes.NewBuffer(reqBody))
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
return req
}
// Add any additional headers // newRequestRaw creates a new request with raw body
for k, v := range headers { func (h *testHarness) newRequestRaw(t *testing.T, method, path string, body io.Reader) *http.Request {
req.Header.Set(k, v) t.Helper()
} return httptest.NewRequest(method, path, body)
}
// executeRequest executes the request and returns response recorder
func (h *testHarness) executeRequest(req *http.Request) *httptest.ResponseRecorder {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
h.Server.Router().ServeHTTP(rr, req) h.Server.Router().ServeHTTP(rr, req)
return rr return rr
} }
// makeRequestRaw is a helper function to make HTTP requests with raw body content // addAuthCookies adds authentication cookies to request
func (h *testHarness) makeRequestRaw(t *testing.T, method, path string, body io.Reader, token string, headers map[string]string) *httptest.ResponseRecorder { func (h *testHarness) addAuthCookies(t *testing.T, req *http.Request, session *models.Session, addCSRF bool) string {
t.Helper() t.Helper()
req := httptest.NewRequest(method, path, body) if session == nil {
if token != "" { return ""
req.Header.Set("Authorization", "Bearer "+token)
} }
// Add any additional headers accessToken, err := h.JWTManager.GenerateAccessToken(session.UserID, "admin")
if err != nil {
t.Fatalf("Failed to generate access token: %v", err)
}
req.AddCookie(h.CookieManager.GenerateAccessTokenCookie(accessToken))
req.AddCookie(h.CookieManager.GenerateRefreshTokenCookie(session.RefreshToken))
if addCSRF {
csrfToken := "test-csrf-token"
req.AddCookie(h.CookieManager.GenerateCSRFCookie(csrfToken))
return csrfToken
}
return ""
}
// makeRequest is the main helper for making JSON requests
func (h *testHarness) makeRequest(t *testing.T, method, path string, body interface{}, session *models.Session, headers map[string]string) *httptest.ResponseRecorder {
t.Helper()
req := h.newRequest(t, method, path, body)
// Add custom headers
for k, v := range headers { for k, v := range headers {
req.Header.Set(k, v) req.Header.Set(k, v)
} }
rr := httptest.NewRecorder() if session != nil {
h.Server.Router().ServeHTTP(rr, req) needsCSRF := method != http.MethodGet && method != http.MethodHead && method != http.MethodOptions
csrfToken := h.addAuthCookies(t, req, session, needsCSRF)
if needsCSRF {
req.Header.Set("X-CSRF-Token", csrfToken)
}
}
return rr return h.executeRequest(req)
}
// 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, headers map[string]string) *httptest.ResponseRecorder {
t.Helper()
req := h.newRequestRaw(t, method, path, body)
// Add custom headers
for k, v := range headers {
req.Header.Set(k, v)
}
if session != nil {
needsCSRF := method != http.MethodGet && method != http.MethodHead && method != http.MethodOptions
csrfToken := h.addAuthCookies(t, req, session, needsCSRF)
if needsCSRF {
req.Header.Set("X-CSRF-Token", csrfToken)
}
}
return h.executeRequest(req)
} }

View File

@@ -23,7 +23,7 @@ func TestUserHandlers_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", func(t *testing.T) { t.Run("successful get", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, h.RegularSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var user models.User var user models.User
@@ -38,7 +38,7 @@ func TestUserHandlers_Integration(t *testing.T) {
}) })
t.Run("unauthorized", func(t *testing.T) { t.Run("unauthorized", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, "", nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/auth/me", nil, nil, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
}) })
@@ -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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
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
@@ -109,7 +109,7 @@ func TestUserHandlers_Integration(t *testing.T) {
Password: "newpassword123", Password: "newpassword123",
} }
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, "", nil) rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, nil, nil)
assert.Equal(t, http.StatusOK, rr.Code) assert.Equal(t, http.StatusOK, rr.Code)
currentPassword = updateReq.NewPassword currentPassword = updateReq.NewPassword
@@ -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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -140,7 +140,7 @@ func TestUserHandlers_Integration(t *testing.T) {
NewPassword: "short", NewPassword: "short",
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
assert.Equal(t, http.StatusBadRequest, rr.Code) assert.Equal(t, http.StatusBadRequest, rr.Code)
}) })
@@ -150,7 +150,7 @@ func TestUserHandlers_Integration(t *testing.T) {
CurrentPassword: currentPassword, CurrentPassword: currentPassword,
} }
rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/profile", updateReq, h.RegularSession, nil)
assert.Equal(t, http.StatusConflict, rr.Code) assert.Equal(t, http.StatusConflict, rr.Code)
}) })
}) })
@@ -164,37 +164,44 @@ func TestUserHandlers_Integration(t *testing.T) {
Role: models.RoleEditor, Role: models.RoleEditor,
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/admin/users", createReq, h.AdminSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var newUser models.User var newUser models.User
err := json.NewDecoder(rr.Body).Decode(&newUser) err := json.NewDecoder(rr.Body).Decode(&newUser)
require.NoError(t, err) require.NoError(t, err)
// Get token for new user // Get session for new user
loginReq := handlers.LoginRequest{ loginReq := handlers.LoginRequest{
Email: createReq.Email, Email: createReq.Email,
Password: createReq.Password, Password: createReq.Password,
} }
rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, "", nil) rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, nil, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var loginResp handlers.LoginResponse var loginResp handlers.LoginResponse
err = json.NewDecoder(rr.Body).Decode(&loginResp) err = json.NewDecoder(rr.Body).Decode(&loginResp)
require.NoError(t, err) require.NoError(t, err)
userToken := loginResp.AccessToken
// 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: createReq.Password,
} }
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, userToken, nil) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, userSession, nil)
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) rr = h.makeRequest(t, http.MethodPost, "/api/v1/auth/login", loginReq, nil, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -203,7 +210,7 @@ func TestUserHandlers_Integration(t *testing.T) {
Password: "wrongpassword", Password: "wrongpassword",
} }
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, h.RegularSession, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
@@ -212,7 +219,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.AdminToken, nil) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/profile", deleteReq, h.AdminSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, h.RegularSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var workspaces []*models.Workspace var workspaces []*models.Workspace
@@ -30,7 +30,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
}) })
t.Run("unauthorized", func(t *testing.T) { t.Run("unauthorized", func(t *testing.T) {
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, "", nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, nil, nil)
assert.Equal(t, http.StatusUnauthorized, rr.Code) assert.Equal(t, http.StatusUnauthorized, rr.Code)
}) })
}) })
@@ -41,7 +41,7 @@ func TestWorkspaceHandlers_Integration(t *testing.T) {
Name: "Test Workspace", Name: "Test Workspace",
} }
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, http.StatusOK, rr.Code)
var created models.Workspace var created models.Workspace
@@ -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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/nonexistent", nil, h.RegularSession, nil)
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.AdminToken, nil) rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.AdminSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, baseURL, workspace, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/last", nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPut, "/api/v1/workspaces/last", req, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/last", nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", newWorkspace, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(newWorkspace.Name), nil, h.RegularSession, nil)
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.RegularToken, nil) rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/"+url.PathEscape(newWorkspace.Name), nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(ws.Name), nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(lastWs.Name), nil, h.RegularSession, nil)
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.RegularToken, nil) rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularSession, nil)
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.AdminToken, nil) rr = h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(workspace.Name), nil, h.AdminSession, nil)
assert.Equal(t, http.StatusNotFound, rr.Code) assert.Equal(t, http.StatusNotFound, rr.Code)
}) })
}) })