Add configuration files and update project documentation
- Introduced .editorconfig for consistent coding styles across the project. - Added .golangci.yml for Go linting configuration. - Updated AGENTS.md to clarify project structure and components. - Enhanced CONTRIBUTING.md with Makefile usage for common tasks. - Updated Dockerfiles to use Go 1.24 and improved build instructions. - Refined README.md and deployment documentation for clarity. - Added testing documentation in testing.md for backend and frontend tests. - Introduced Makefile for streamlined development commands and tasks.
This commit is contained in:
558
internal/app/handlers/handlers_test.go
Normal file
558
internal/app/handlers/handlers_test.go
Normal file
@@ -0,0 +1,558 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/andyleap/hnh-map/internal/app"
|
||||
"github.com/andyleap/hnh-map/internal/app/apperr"
|
||||
"github.com/andyleap/hnh-map/internal/app/handlers"
|
||||
"github.com/andyleap/hnh-map/internal/app/services"
|
||||
"github.com/andyleap/hnh-map/internal/app/store"
|
||||
"go.etcd.io/bbolt"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type testEnv struct {
|
||||
h *handlers.Handlers
|
||||
st *store.Store
|
||||
auth *services.AuthService
|
||||
}
|
||||
|
||||
func newTestEnv(t *testing.T) *testEnv {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
db, err := bbolt.Open(filepath.Join(dir, "test.db"), 0600, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { db.Close() })
|
||||
|
||||
st := store.New(db)
|
||||
auth := services.NewAuthService(st)
|
||||
gridUpdates := &app.Topic[app.TileData]{}
|
||||
mergeUpdates := &app.Topic[app.Merge]{}
|
||||
|
||||
mapSvc := services.NewMapService(services.MapServiceDeps{
|
||||
Store: st,
|
||||
GridStorage: dir,
|
||||
GridUpdates: gridUpdates,
|
||||
MergeUpdates: mergeUpdates,
|
||||
GetChars: func() []app.Character { return nil },
|
||||
})
|
||||
admin := services.NewAdminService(st, mapSvc)
|
||||
client := services.NewClientService(services.ClientServiceDeps{
|
||||
Store: st,
|
||||
MapSvc: mapSvc,
|
||||
WithChars: func(fn func(chars map[string]app.Character)) { fn(map[string]app.Character{}) },
|
||||
})
|
||||
export := services.NewExportService(st, mapSvc)
|
||||
|
||||
h := handlers.New(auth, mapSvc, admin, client, export)
|
||||
return &testEnv{h: h, st: st, auth: auth}
|
||||
}
|
||||
|
||||
func (env *testEnv) createUser(t *testing.T, username, password string, auths app.Auths) {
|
||||
t.Helper()
|
||||
hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost)
|
||||
u := app.User{Pass: hash, Auths: auths}
|
||||
raw, _ := json.Marshal(u)
|
||||
env.st.Update(context.Background(), func(tx *bbolt.Tx) error {
|
||||
return env.st.PutUser(tx, username, raw)
|
||||
})
|
||||
}
|
||||
|
||||
func (env *testEnv) loginSession(t *testing.T, username string) string {
|
||||
t.Helper()
|
||||
return env.auth.CreateSession(context.Background(), username, false)
|
||||
}
|
||||
|
||||
func withSession(req *http.Request, sid string) *http.Request {
|
||||
req.AddCookie(&http.Cookie{Name: "session", Value: sid})
|
||||
return req
|
||||
}
|
||||
|
||||
func TestAPISetup_NoUsers(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/setup", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APISetup(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
|
||||
var resp struct{ SetupRequired bool }
|
||||
json.NewDecoder(rr.Body).Decode(&resp)
|
||||
if !resp.SetupRequired {
|
||||
t.Fatal("expected setupRequired=true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPISetup_WithUsers(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/setup", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APISetup(rr, req)
|
||||
|
||||
var resp struct{ SetupRequired bool }
|
||||
json.NewDecoder(rr.Body).Decode(&resp)
|
||||
if resp.SetupRequired {
|
||||
t.Fatal("expected setupRequired=false with users")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPISetup_WrongMethod(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodPost, "/map/api/setup", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APISetup(rr, req)
|
||||
if rr.Code != http.StatusMethodNotAllowed {
|
||||
t.Fatalf("expected 405, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPILogin_Success(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "secret", app.Auths{app.AUTH_MAP})
|
||||
|
||||
body := `{"user":"alice","pass":"secret"}`
|
||||
req := httptest.NewRequest(http.MethodPost, "/map/api/login", strings.NewReader(body))
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APILogin(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
cookies := rr.Result().Cookies()
|
||||
found := false
|
||||
for _, c := range cookies {
|
||||
if c.Name == "session" && c.Value != "" {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("expected session cookie")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPILogin_WrongPassword(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "secret", app.Auths{app.AUTH_MAP})
|
||||
|
||||
body := `{"user":"alice","pass":"wrong"}`
|
||||
req := httptest.NewRequest(http.MethodPost, "/map/api/login", strings.NewReader(body))
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APILogin(rr, req)
|
||||
|
||||
if rr.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPILogin_BadJSON(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodPost, "/map/api/login", strings.NewReader("{invalid"))
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APILogin(rr, req)
|
||||
if rr.Code != http.StatusBadRequest {
|
||||
t.Fatalf("expected 400, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPILogin_MethodNotAllowed(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/login", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APILogin(rr, req)
|
||||
if rr.Code != http.StatusMethodNotAllowed {
|
||||
t.Fatalf("expected 405, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIMe_Authenticated(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_MAP, app.AUTH_UPLOAD})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/me", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIMe(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
Username string `json:"username"`
|
||||
Auths []string `json:"auths"`
|
||||
}
|
||||
json.NewDecoder(rr.Body).Decode(&resp)
|
||||
if resp.Username != "alice" {
|
||||
t.Fatalf("expected alice, got %s", resp.Username)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIMe_Unauthenticated(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/me", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIMe(rr, req)
|
||||
if rr.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPILogout(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", nil)
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodPost, "/map/api/logout", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APILogout(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
|
||||
req2 := withSession(httptest.NewRequest(http.MethodGet, "/map/api/me", nil), sid)
|
||||
rr2 := httptest.NewRecorder()
|
||||
env.h.APIMe(rr2, req2)
|
||||
if rr2.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401 after logout, got %d", rr2.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIMeTokens_Authenticated(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_UPLOAD})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodPost, "/map/api/me/tokens", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIMeTokens(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
var resp struct{ Tokens []string }
|
||||
json.NewDecoder(rr.Body).Decode(&resp)
|
||||
if len(resp.Tokens) != 1 {
|
||||
t.Fatalf("expected 1 token, got %d", len(resp.Tokens))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIMeTokens_Unauthenticated(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodPost, "/map/api/me/tokens", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIMeTokens(rr, req)
|
||||
if rr.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIMeTokens_NoUploadAuth(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_MAP})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodPost, "/map/api/me/tokens", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIMeTokens(rr, req)
|
||||
if rr.Code != http.StatusForbidden {
|
||||
t.Fatalf("expected 403, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIMePassword(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "old", app.Auths{app.AUTH_MAP})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
body := `{"pass":"newpass"}`
|
||||
req := withSession(httptest.NewRequest(http.MethodPost, "/map/api/me/password", strings.NewReader(body)), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIMePassword(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminUsers_RequiresAdmin(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_MAP})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/admin/users", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIAdminUsers(rr, req)
|
||||
if rr.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401 for non-admin, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminUsers_ListAndCreate(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
||||
sid := env.loginSession(t, "admin")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/admin/users", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIAdminUsers(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
|
||||
body := `{"user":"bob","pass":"secret","auths":["map","upload"]}`
|
||||
req2 := withSession(httptest.NewRequest(http.MethodPost, "/map/api/admin/users", strings.NewReader(body)), sid)
|
||||
rr2 := httptest.NewRecorder()
|
||||
env.h.APIAdminUsers(rr2, req2)
|
||||
if rr2.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d: %s", rr2.Code, rr2.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminSettings(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
||||
sid := env.loginSession(t, "admin")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/admin/settings", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIAdminSettingsGet(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
|
||||
body := `{"prefix":"pfx","title":"New Title","defaultHide":true}`
|
||||
req2 := withSession(httptest.NewRequest(http.MethodPost, "/map/api/admin/settings", strings.NewReader(body)), sid)
|
||||
rr2 := httptest.NewRecorder()
|
||||
env.h.APIAdminSettingsPost(rr2, req2)
|
||||
if rr2.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr2.Code)
|
||||
}
|
||||
|
||||
req3 := withSession(httptest.NewRequest(http.MethodGet, "/map/api/admin/settings", nil), sid)
|
||||
rr3 := httptest.NewRecorder()
|
||||
env.h.APIAdminSettingsGet(rr3, req3)
|
||||
|
||||
var resp struct {
|
||||
Prefix string `json:"prefix"`
|
||||
DefaultHide bool `json:"defaultHide"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
json.NewDecoder(rr3.Body).Decode(&resp)
|
||||
if resp.Prefix != "pfx" || !resp.DefaultHide || resp.Title != "New Title" {
|
||||
t.Fatalf("unexpected settings: %+v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminWipe(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
||||
sid := env.loginSession(t, "admin")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodPost, "/map/api/admin/wipe", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIAdminWipe(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminMaps(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
||||
sid := env.loginSession(t, "admin")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/admin/maps", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIAdminMaps(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIRouter_NotFound(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/nonexistent", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIRouter(rr, req)
|
||||
if rr.Code != http.StatusNotFound {
|
||||
t.Fatalf("expected 404, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIRouter_Config(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_MAP})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/config", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIRouter(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetChars_Unauthenticated(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/v1/characters", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIGetChars(rr, req)
|
||||
if rr.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetMarkers_Unauthenticated(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/v1/markers", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIGetMarkers(rr, req)
|
||||
if rr.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetMaps_Unauthenticated(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/map/api/maps", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIGetMaps(rr, req)
|
||||
if rr.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetChars_NoMarkersAuth(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_MAP})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/v1/characters", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIGetChars(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
var chars []interface{}
|
||||
json.NewDecoder(rr.Body).Decode(&chars)
|
||||
if len(chars) != 0 {
|
||||
t.Fatal("expected empty array without markers auth")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIGetMarkers_NoMarkersAuth(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_MAP})
|
||||
sid := env.loginSession(t, "alice")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/v1/markers", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIGetMarkers(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
var markers []interface{}
|
||||
json.NewDecoder(rr.Body).Decode(&markers)
|
||||
if len(markers) != 0 {
|
||||
t.Fatal("expected empty array without markers auth")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedirectLogout(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/logout", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.RedirectLogout(rr, req)
|
||||
if rr.Code != http.StatusFound {
|
||||
t.Fatalf("expected 302, got %d", rr.Code)
|
||||
}
|
||||
if loc := rr.Header().Get("Location"); loc != "/login" {
|
||||
t.Fatalf("expected redirect to /login, got %s", loc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedirectLogout_WrongPath(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/other", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.RedirectLogout(rr, req)
|
||||
if rr.Code != http.StatusNotFound {
|
||||
t.Fatalf("expected 404, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleServiceError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
err error
|
||||
status int
|
||||
}{
|
||||
{"not found", apperr.ErrNotFound, http.StatusNotFound},
|
||||
{"unauthorized", apperr.ErrUnauthorized, http.StatusUnauthorized},
|
||||
{"forbidden", apperr.ErrForbidden, http.StatusForbidden},
|
||||
{"bad request", apperr.ErrBadRequest, http.StatusBadRequest},
|
||||
{"oauth only", apperr.ErrOAuthOnly, http.StatusUnauthorized},
|
||||
{"provider unconfigured", apperr.ErrProviderUnconfigured, http.StatusServiceUnavailable},
|
||||
{"state expired", apperr.ErrStateExpired, http.StatusBadRequest},
|
||||
{"exchange failed", apperr.ErrExchangeFailed, http.StatusBadGateway},
|
||||
{"unknown", errors.New("something else"), http.StatusInternalServerError},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
handlers.HandleServiceError(rr, tt.err)
|
||||
if rr.Code != tt.status {
|
||||
t.Fatalf("expected %d, got %d", tt.status, rr.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminUserByName(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
||||
env.createUser(t, "bob", "pass", app.Auths{app.AUTH_MAP, app.AUTH_UPLOAD})
|
||||
sid := env.loginSession(t, "admin")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodGet, "/map/api/admin/users/bob", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIAdminUserByName(rr, req, "bob")
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
var resp struct {
|
||||
Username string `json:"username"`
|
||||
Auths []string `json:"auths"`
|
||||
}
|
||||
json.NewDecoder(rr.Body).Decode(&resp)
|
||||
if resp.Username != "bob" {
|
||||
t.Fatalf("expected bob, got %s", resp.Username)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminUserDelete(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
env.createUser(t, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
||||
env.createUser(t, "bob", "pass", app.Auths{app.AUTH_MAP})
|
||||
sid := env.loginSession(t, "admin")
|
||||
|
||||
req := withSession(httptest.NewRequest(http.MethodDelete, "/map/api/admin/users/bob", nil), sid)
|
||||
rr := httptest.NewRecorder()
|
||||
env.h.APIAdminUserDelete(rr, req, "bob")
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user