256 lines
7.5 KiB
Go
256 lines
7.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/DigitalTolk/wireguard-ui/model"
|
|
"github.com/DigitalTolk/wireguard-ui/util"
|
|
)
|
|
|
|
func TestAPIListUsers(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
|
|
req, rec := jsonRequest(http.MethodGet, "/api/v1/users", nil)
|
|
c := env.echo.NewContext(req, rec)
|
|
err := APIListUsers(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
}
|
|
|
|
func TestAPIGetUser(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
now := time.Now().UTC()
|
|
|
|
env.db.SaveUser(model.User{Username: "getme", Email: "get@test.com", CreatedAt: now, UpdatedAt: now})
|
|
|
|
req, rec := jsonRequest(http.MethodGet, "/api/v1/users/getme", nil)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("getme")
|
|
err := APIGetUser(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
}
|
|
|
|
func TestAPIGetUser_NotFound(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
|
|
req, rec := jsonRequest(http.MethodGet, "/api/v1/users/nonexistent", nil)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("nonexistent")
|
|
err := APIGetUser(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusNotFound, rec.Code)
|
|
}
|
|
|
|
func TestAPIListUsers_WithPopulatedData(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
now := time.Now().UTC()
|
|
|
|
env.db.SaveUser(model.User{Username: "user1", Email: "user1@test.com", Admin: true, OIDCSub: "sub-1", CreatedAt: now, UpdatedAt: now})
|
|
env.db.SaveUser(model.User{Username: "user2", Email: "user2@test.com", Admin: false, OIDCSub: "sub-2", CreatedAt: now, UpdatedAt: now})
|
|
env.db.SaveUser(model.User{Username: "user3", Email: "user3@test.com", Admin: false, OIDCSub: "sub-3", CreatedAt: now, UpdatedAt: now})
|
|
|
|
req, rec := jsonRequest(http.MethodGet, "/api/v1/users", nil)
|
|
c := env.echo.NewContext(req, rec)
|
|
err := APIListUsers(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var users []model.User
|
|
parseJSON(t, rec, &users)
|
|
assert.Len(t, users, 3)
|
|
}
|
|
|
|
func TestAPIGetUser_WithFullData(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
now := time.Now().UTC()
|
|
|
|
env.db.SaveUser(model.User{
|
|
Username: "fulluser",
|
|
Email: "full@test.com",
|
|
DisplayName: "Full User",
|
|
OIDCSub: "sub-full",
|
|
Admin: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
})
|
|
|
|
req, rec := jsonRequest(http.MethodGet, "/api/v1/users/fulluser", nil)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("fulluser")
|
|
err := APIGetUser(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var user model.User
|
|
parseJSON(t, rec, &user)
|
|
assert.Equal(t, "fulluser", user.Username)
|
|
assert.Equal(t, "full@test.com", user.Email)
|
|
assert.Equal(t, "Full User", user.DisplayName)
|
|
assert.True(t, user.Admin)
|
|
}
|
|
|
|
func TestAPIListUsers_DBError(t *testing.T) {
|
|
db := &errStore{}
|
|
e := echo.New()
|
|
|
|
req, rec := jsonRequest(http.MethodGet, "/api/v1/users", nil)
|
|
c := e.NewContext(req, rec)
|
|
err := APIListUsers(db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
}
|
|
|
|
func TestAPIGetUser_InvalidUsername(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
|
|
req, rec := jsonRequest(http.MethodGet, "/api/v1/users/baduser", nil)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("bad user!")
|
|
err := APIGetUser(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusBadRequest, rec.Code)
|
|
}
|
|
|
|
// --- APIPatchUserAdmin tests ---
|
|
|
|
func TestAPIPatchUserAdmin_PromoteSuccess(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
now := time.Now().UTC()
|
|
|
|
env.db.SaveUser(model.User{Username: "patchuser", Email: "patch@test.com", Admin: false, OIDCSub: "sub-patch", CreatedAt: now, UpdatedAt: now})
|
|
|
|
body := map[string]interface{}{"admin": true}
|
|
req, rec := jsonRequest(http.MethodPatch, "/api/v1/users/patchuser/admin", body)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("patchuser")
|
|
|
|
err := APIPatchUserAdmin(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var result model.User
|
|
parseJSON(t, rec, &result)
|
|
assert.True(t, result.Admin)
|
|
assert.Equal(t, "patchuser", result.Username)
|
|
|
|
// Verify CRC32 cache was updated
|
|
util.DBUsersToCRC32Mutex.RLock()
|
|
_, ok := util.DBUsersToCRC32["patchuser"]
|
|
util.DBUsersToCRC32Mutex.RUnlock()
|
|
assert.True(t, ok, "CRC32 cache should be updated after admin change")
|
|
}
|
|
|
|
func TestAPIPatchUserAdmin_DemoteSuccess(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
now := time.Now().UTC()
|
|
|
|
env.db.SaveUser(model.User{Username: "demoteuser", Email: "demote@test.com", Admin: true, OIDCSub: "sub-demote", CreatedAt: now, UpdatedAt: now})
|
|
|
|
body := map[string]interface{}{"admin": false}
|
|
req, rec := jsonRequest(http.MethodPatch, "/api/v1/users/demoteuser/admin", body)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("demoteuser")
|
|
|
|
err := APIPatchUserAdmin(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var result model.User
|
|
parseJSON(t, rec, &result)
|
|
assert.False(t, result.Admin)
|
|
}
|
|
|
|
func TestAPIPatchUserAdmin_InvalidUsername(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
|
|
body := map[string]interface{}{"admin": true}
|
|
req, rec := jsonRequest(http.MethodPatch, "/api/v1/users/baduser/admin", body)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("bad user!")
|
|
|
|
err := APIPatchUserAdmin(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusBadRequest, rec.Code)
|
|
}
|
|
|
|
func TestAPIPatchUserAdmin_UserNotFound(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
|
|
body := map[string]interface{}{"admin": true}
|
|
req, rec := jsonRequest(http.MethodPatch, "/api/v1/users/nonexistent/admin", body)
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("nonexistent")
|
|
|
|
err := APIPatchUserAdmin(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusNotFound, rec.Code)
|
|
}
|
|
|
|
func TestAPIPatchUserAdmin_InvalidBody(t *testing.T) {
|
|
env := setupTestEnv(t)
|
|
|
|
// Send a request with invalid JSON body
|
|
req := httptest.NewRequest(http.MethodPatch, "/api/v1/users/someuser/admin", strings.NewReader("{invalid"))
|
|
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
|
|
rec := httptest.NewRecorder()
|
|
c := env.echo.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("someuser")
|
|
|
|
err := APIPatchUserAdmin(env.db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusBadRequest, rec.Code)
|
|
}
|
|
|
|
func TestAPIPatchUserAdmin_DBSaveError(t *testing.T) {
|
|
db := &errStore{}
|
|
e := echo.New()
|
|
|
|
body := map[string]interface{}{"admin": true}
|
|
req, rec := jsonRequest(http.MethodPatch, "/api/v1/users/anyuser/admin", body)
|
|
c := e.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("anyuser")
|
|
|
|
err := APIPatchUserAdmin(db)(c)
|
|
require.NoError(t, err)
|
|
// errStore.GetUserByName returns error, so we get 404
|
|
assert.Equal(t, http.StatusNotFound, rec.Code)
|
|
}
|
|
|
|
func TestAPIPatchUserAdmin_SaveUserFails(t *testing.T) {
|
|
// Use saveFailStore: GetUserByName succeeds, SaveUser fails
|
|
now := time.Now().UTC()
|
|
db := &saveFailStore{
|
|
user: model.User{Username: "saveuser", Email: "save@test.com", Admin: false, CreatedAt: now, UpdatedAt: now},
|
|
}
|
|
e := echo.New()
|
|
|
|
body := map[string]interface{}{"admin": true}
|
|
req, rec := jsonRequest(http.MethodPatch, "/api/v1/users/saveuser/admin", body)
|
|
c := e.NewContext(req, rec)
|
|
c.SetParamNames("username")
|
|
c.SetParamValues("saveuser")
|
|
|
|
err := APIPatchUserAdmin(db)(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
}
|