Files
hnh-map/internal/app/handlers/handlers_test.go
Nikolay Tatarinov 8f769543f4 Refactor frontend components and enhance API integration
- Updated frontend-nuxt.mdc to specify usage of composables for API calls.
- Added new AuthCard and ConfirmModal components for improved UI consistency.
- Introduced UserAvatar component for user profile display, replacing previous Gravatar implementation.
- Implemented useFormSubmit composable for handling form submissions with loading and error states.
- Enhanced vitest.config.ts to include coverage reporting for composables and components.
- Removed deprecated useAdminApi and useAuth composables to streamline API interactions.
- Updated login and setup pages to utilize new components and composables for better user experience.
2026-03-04 00:14:05 +03:00

680 lines
21 KiB
Go

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 TestAPIMeUpdate_UpdatesEmail(t *testing.T) {
env := newTestEnv(t)
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_MAP})
sid := env.loginSession(t, "alice")
patchBody := `{"email":"test@example.com"}`
req := withSession(httptest.NewRequest(http.MethodPatch, "/map/api/me", strings.NewReader(patchBody)), sid)
req.Header.Set("Content-Type", "application/json")
rr := httptest.NewRecorder()
env.h.APIMeUpdate(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
}
req2 := withSession(httptest.NewRequest(http.MethodGet, "/map/api/me", nil), sid)
rr2 := httptest.NewRecorder()
env.h.APIMe(rr2, req2)
if rr2.Code != http.StatusOK {
t.Fatalf("expected 200 on GET /me, got %d", rr2.Code)
}
var meResp struct {
Username string `json:"username"`
Email string `json:"email"`
}
if err := json.NewDecoder(rr2.Body).Decode(&meResp); err != nil {
t.Fatal(err)
}
if meResp.Email != "test@example.com" {
t.Fatalf("expected email test@example.com, got %q", meResp.Email)
}
}
func TestAPIRouter_Me_MethodNotAllowed(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", nil), sid)
rr := httptest.NewRecorder()
env.h.APIRouter(rr, req)
if rr.Code != http.StatusMethodNotAllowed {
t.Fatalf("expected 405 for POST /me, 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)
}
}
func TestClientRouter_Locate(t *testing.T) {
env := newTestEnv(t)
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_UPLOAD})
ctx := context.Background()
tokens := env.auth.GenerateTokenForUser(ctx, "alice")
if len(tokens) == 0 {
t.Fatal("expected token")
}
gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 2, Y: 3}}
raw, _ := json.Marshal(gd)
env.st.Update(ctx, func(tx *bbolt.Tx) error {
return env.st.PutGrid(tx, "g1", raw)
})
req := httptest.NewRequest(http.MethodGet, "/client/"+tokens[0]+"/locate?gridID=g1", nil)
rr := httptest.NewRecorder()
env.h.ClientRouter(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
}
if body := strings.TrimSpace(rr.Body.String()); body != "1;2;3" {
t.Fatalf("expected body 1;2;3, got %q", body)
}
}
func TestClientRouter_Locate_NotFound(t *testing.T) {
env := newTestEnv(t)
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_UPLOAD})
tokens := env.auth.GenerateTokenForUser(context.Background(), "alice")
if len(tokens) == 0 {
t.Fatal("expected token")
}
req := httptest.NewRequest(http.MethodGet, "/client/"+tokens[0]+"/locate?gridID=ghost", nil)
rr := httptest.NewRecorder()
env.h.ClientRouter(rr, req)
if rr.Code != http.StatusNotFound {
t.Fatalf("expected 404, got %d", rr.Code)
}
}
func TestClientRouter_CheckVersion(t *testing.T) {
env := newTestEnv(t)
env.createUser(t, "alice", "pass", app.Auths{app.AUTH_UPLOAD})
tokens := env.auth.GenerateTokenForUser(context.Background(), "alice")
if len(tokens) == 0 {
t.Fatal("expected token")
}
req := httptest.NewRequest(http.MethodGet, "/client/"+tokens[0]+"/checkVersion?version="+app.ClientVersion, nil)
rr := httptest.NewRecorder()
env.h.ClientRouter(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected 200 for matching version, got %d", rr.Code)
}
req2 := httptest.NewRequest(http.MethodGet, "/client/"+tokens[0]+"/checkVersion?version=other", nil)
rr2 := httptest.NewRecorder()
env.h.ClientRouter(rr2, req2)
if rr2.Code != http.StatusBadRequest {
t.Fatalf("expected 400 for wrong version, got %d", rr2.Code)
}
}
func TestClientRouter_InvalidToken(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/client/badtoken/locate?gridID=g1", nil)
rr := httptest.NewRecorder()
env := newTestEnv(t)
env.h.ClientRouter(rr, req)
if rr.Code != http.StatusUnauthorized {
t.Fatalf("expected 401, got %d", rr.Code)
}
}