mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
Implement workspace handlers integration tests
This commit is contained in:
297
server/internal/handlers/workspace_handlers_integration_test.go
Normal file
297
server/internal/handlers/workspace_handlers_integration_test.go
Normal file
@@ -0,0 +1,297 @@
|
||||
//go:build integration
|
||||
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"novamd/internal/models"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWorkspaceHandlers_Integration(t *testing.T) {
|
||||
h := setupTestHarness(t)
|
||||
defer h.teardown(t)
|
||||
|
||||
t.Run("list workspaces", 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)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var workspaces []*models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&workspaces)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, workspaces, "User should have at least one default workspace")
|
||||
})
|
||||
|
||||
t.Run("unauthorized", func(t *testing.T) {
|
||||
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, "", nil)
|
||||
assert.Equal(t, http.StatusUnauthorized, rr.Code)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("create workspace", func(t *testing.T) {
|
||||
t.Run("successful create", func(t *testing.T) {
|
||||
workspace := &models.Workspace{
|
||||
Name: "Test Workspace",
|
||||
}
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var created models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&created)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, workspace.Name, created.Name)
|
||||
assert.Equal(t, h.RegularUser.ID, created.UserID)
|
||||
assert.NotZero(t, created.ID)
|
||||
})
|
||||
|
||||
t.Run("create with git settings", func(t *testing.T) {
|
||||
workspace := &models.Workspace{
|
||||
Name: "Git Workspace",
|
||||
GitEnabled: true,
|
||||
GitURL: "https://github.com/test/repo.git",
|
||||
GitUser: "testuser",
|
||||
GitToken: "testtoken",
|
||||
GitAutoCommit: true,
|
||||
}
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var created models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&created)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, workspace.GitEnabled, created.GitEnabled)
|
||||
assert.Equal(t, workspace.GitURL, created.GitURL)
|
||||
assert.Equal(t, workspace.GitUser, created.GitUser)
|
||||
assert.Equal(t, workspace.GitToken, created.GitToken)
|
||||
assert.Equal(t, workspace.GitAutoCommit, created.GitAutoCommit)
|
||||
})
|
||||
|
||||
t.Run("invalid workspace", func(t *testing.T) {
|
||||
workspace := &models.Workspace{
|
||||
Name: "", // Empty name
|
||||
GitEnabled: true,
|
||||
// Missing required Git settings
|
||||
}
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil)
|
||||
assert.Equal(t, http.StatusBadRequest, rr.Code)
|
||||
})
|
||||
})
|
||||
|
||||
// Create a workspace for the remaining tests
|
||||
workspace := &models.Workspace{
|
||||
Name: "Test Workspace Operations",
|
||||
}
|
||||
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
err := json.NewDecoder(rr.Body).Decode(workspace)
|
||||
require.NoError(t, err)
|
||||
|
||||
escapedName := url.PathEscape(workspace.Name)
|
||||
baseURL := "/api/v1/workspaces/" + escapedName
|
||||
|
||||
t.Run("get workspace", func(t *testing.T) {
|
||||
t.Run("successful get", func(t *testing.T) {
|
||||
rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var got models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&got)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, workspace.ID, got.ID)
|
||||
assert.Equal(t, workspace.Name, got.Name)
|
||||
})
|
||||
|
||||
t.Run("nonexistent workspace", func(t *testing.T) {
|
||||
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/nonexistent", nil, h.RegularToken, nil)
|
||||
assert.Equal(t, http.StatusNotFound, rr.Code)
|
||||
})
|
||||
|
||||
t.Run("unauthorized access", func(t *testing.T) {
|
||||
// Try accessing with another user's token
|
||||
rr := h.makeRequest(t, http.MethodGet, baseURL, nil, h.AdminToken, nil)
|
||||
assert.Equal(t, http.StatusNotFound, rr.Code)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("update workspace", func(t *testing.T) {
|
||||
t.Run("update name", func(t *testing.T) {
|
||||
workspace.Name = "Updated Workspace"
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPut, baseURL, workspace, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var updated models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&updated)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, workspace.Name, updated.Name)
|
||||
|
||||
// Update baseURL for remaining tests
|
||||
escapedName = url.PathEscape(workspace.Name)
|
||||
baseURL = "/api/v1/workspaces/" + escapedName
|
||||
})
|
||||
|
||||
t.Run("update settings", func(t *testing.T) {
|
||||
update := &models.Workspace{
|
||||
Name: workspace.Name,
|
||||
Theme: "dark",
|
||||
AutoSave: true,
|
||||
ShowHiddenFiles: true,
|
||||
}
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var updated models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&updated)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, update.Theme, updated.Theme)
|
||||
assert.Equal(t, update.AutoSave, updated.AutoSave)
|
||||
assert.Equal(t, update.ShowHiddenFiles, updated.ShowHiddenFiles)
|
||||
})
|
||||
|
||||
t.Run("enable git", func(t *testing.T) {
|
||||
update := &models.Workspace{
|
||||
Name: workspace.Name,
|
||||
Theme: "dark",
|
||||
GitEnabled: true,
|
||||
GitURL: "https://github.com/test/repo.git",
|
||||
GitUser: "testuser",
|
||||
GitToken: "testtoken",
|
||||
GitAutoCommit: true,
|
||||
}
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var updated models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&updated)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, update.GitEnabled, updated.GitEnabled)
|
||||
assert.Equal(t, update.GitURL, updated.GitURL)
|
||||
assert.Equal(t, update.GitUser, updated.GitUser)
|
||||
assert.Equal(t, update.GitToken, updated.GitToken)
|
||||
|
||||
// Mock should have been called to setup git
|
||||
assert.True(t, h.MockGit.IsInitialized())
|
||||
})
|
||||
|
||||
t.Run("invalid git settings", func(t *testing.T) {
|
||||
update := &models.Workspace{
|
||||
Name: workspace.Name,
|
||||
GitEnabled: true,
|
||||
// Missing required Git settings
|
||||
}
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPut, baseURL, update, h.RegularToken, nil)
|
||||
assert.Equal(t, http.StatusBadRequest, rr.Code)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("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)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var response struct {
|
||||
LastWorkspaceName string `json:"lastWorkspaceName"`
|
||||
}
|
||||
err := json.NewDecoder(rr.Body).Decode(&response)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, response.LastWorkspaceName)
|
||||
})
|
||||
|
||||
t.Run("update last workspace", func(t *testing.T) {
|
||||
req := struct {
|
||||
WorkspaceName string `json:"workspaceName"`
|
||||
}{
|
||||
WorkspaceName: workspace.Name,
|
||||
}
|
||||
|
||||
rr := h.makeRequest(t, http.MethodPut, "/api/v1/workspaces/last", req, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
// Verify the update
|
||||
rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/last", nil, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var response struct {
|
||||
LastWorkspaceName string `json:"lastWorkspaceName"`
|
||||
}
|
||||
err := json.NewDecoder(rr.Body).Decode(&response)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, workspace.Name, response.LastWorkspaceName)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("delete workspace", func(t *testing.T) {
|
||||
// Get current workspaces to know how many we have
|
||||
rr := h.makeRequest(t, http.MethodGet, "/api/v1/workspaces", nil, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var existingWorkspaces []*models.Workspace
|
||||
err := json.NewDecoder(rr.Body).Decode(&existingWorkspaces)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a new workspace we can safely delete
|
||||
newWorkspace := &models.Workspace{
|
||||
Name: "Workspace To Delete",
|
||||
}
|
||||
rr = h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", newWorkspace, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
err = json.NewDecoder(rr.Body).Decode(newWorkspace)
|
||||
require.NoError(t, err)
|
||||
|
||||
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)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var response struct {
|
||||
NextWorkspaceName string `json:"nextWorkspaceName"`
|
||||
}
|
||||
err := json.NewDecoder(rr.Body).Decode(&response)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, response.NextWorkspaceName)
|
||||
|
||||
// Verify workspace is deleted
|
||||
rr = h.makeRequest(t, http.MethodGet, "/api/v1/workspaces/"+url.PathEscape(newWorkspace.Name), nil, h.RegularToken, nil)
|
||||
assert.Equal(t, http.StatusNotFound, rr.Code)
|
||||
})
|
||||
|
||||
t.Run("prevent deleting last workspace", func(t *testing.T) {
|
||||
// Delete all but one workspace
|
||||
for i := 0; i < len(existingWorkspaces)-1; i++ {
|
||||
ws := existingWorkspaces[i]
|
||||
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(ws.Name), nil, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
}
|
||||
|
||||
// Try to delete the last remaining workspace
|
||||
lastWs := existingWorkspaces[len(existingWorkspaces)-1]
|
||||
rr := h.makeRequest(t, http.MethodDelete, "/api/v1/workspaces/"+url.PathEscape(lastWs.Name), nil, h.RegularToken, nil)
|
||||
assert.Equal(t, http.StatusBadRequest, rr.Code)
|
||||
})
|
||||
|
||||
t.Run("unauthorized deletion", func(t *testing.T) {
|
||||
// Create a workspace to attempt unauthorized deletion
|
||||
workspace := &models.Workspace{
|
||||
Name: "Unauthorized Delete Test",
|
||||
}
|
||||
rr := h.makeRequest(t, http.MethodPost, "/api/v1/workspaces", workspace, h.RegularToken, nil)
|
||||
require.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
// 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)
|
||||
assert.Equal(t, http.StatusNotFound, rr.Code)
|
||||
})
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user