test(backend): add unit and integration tests for folder browsing
- Add unit tests in internal/services/library_service_test.go - Test path traversal protection - Test non-existent path handling - Test file vs directory validation - Test successful directory listing - Add integration tests in cmd/server/tests/library_browse_test.go - Use setupTestServer() helper from test_helpers.go - Test no authentication returns 401 - Test regular user returns 403 forbidden - Test admin can browse directories - Test path traversal blocking - All tests use table-driven approach with t.Run() Fixes: Issue 2 (tests)
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBrowseLibraryFoldersEndpoint(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
defer setup.Close()
|
||||
|
||||
t.Run("GET /api/libraries/browse - no authentication returns 401", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/libraries/browse?path=/tmp", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||
assert.Equal(t, http.StatusUnauthorized, rec.Code)
|
||||
})
|
||||
|
||||
t.Run("GET /api/libraries/browse - regular user returns 403 forbidden", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/libraries/browse?path=/tmp", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.RegularToken)
|
||||
rec := httptest.NewRecorder()
|
||||
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||
assert.Equal(t, http.StatusForbidden, rec.Code)
|
||||
})
|
||||
|
||||
t.Run("GET /api/libraries/browse - admin can browse directories", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/libraries/browse?path=/tmp", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.Token)
|
||||
rec := httptest.NewRecorder()
|
||||
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
var data struct {
|
||||
CurrentPath string `json:"current_path"`
|
||||
ParentPath string `json:"parent_path"`
|
||||
Directories []string `json:"directories"`
|
||||
}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "/tmp", data.CurrentPath)
|
||||
assert.NotEmpty(t, data.Directories)
|
||||
})
|
||||
|
||||
t.Run("GET /api/libraries/browse - blocks path traversal attempts", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/libraries/browse?path=/etc/../root", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.Token)
|
||||
rec := httptest.NewRecorder()
|
||||
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||
assert.Equal(t, http.StatusBadRequest, rec.Code)
|
||||
|
||||
var errResp struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
json.Unmarshal(rec.Body.Bytes(), &errResp)
|
||||
assert.Contains(t, errResp.Error, "path traversal not allowed")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBrowseDirectories(t *testing.T) {
|
||||
service := &LibraryService{}
|
||||
|
||||
t.Run("blocks path traversal with ..", func(t *testing.T) {
|
||||
_, _, _, err := service.BrowseDirectories(context.Background(), "/etc/../root")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "path traversal not allowed")
|
||||
})
|
||||
|
||||
t.Run("returns error for non-existent path", func(t *testing.T) {
|
||||
_, _, _, err := service.BrowseDirectories(context.Background(), "/nonexistent/path")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "path does not exist")
|
||||
})
|
||||
|
||||
t.Run("returns error when path is a file", func(t *testing.T) {
|
||||
_, _, _, err := service.BrowseDirectories(context.Background(), "/etc/passwd")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "not a directory")
|
||||
})
|
||||
|
||||
t.Run("returns subdirectories for valid path", func(t *testing.T) {
|
||||
dirs, currentPath, parentPath, err := service.BrowseDirectories(context.Background(), "/tmp")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, dirs)
|
||||
assert.Equal(t, "/tmp", currentPath)
|
||||
assert.Equal(t, "/", parentPath)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user