- 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.
293 lines
6.8 KiB
Go
293 lines
6.8 KiB
Go
package services_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/andyleap/hnh-map/internal/app"
|
|
"github.com/andyleap/hnh-map/internal/app/services"
|
|
"github.com/andyleap/hnh-map/internal/app/store"
|
|
"go.etcd.io/bbolt"
|
|
)
|
|
|
|
func newTestAdmin(t *testing.T) (*services.AdminService, *store.Store) {
|
|
t.Helper()
|
|
db := newTestDB(t)
|
|
st := store.New(db)
|
|
mapSvc := services.NewMapService(services.MapServiceDeps{
|
|
Store: st,
|
|
GridStorage: t.TempDir(),
|
|
GridUpdates: &app.Topic[app.TileData]{},
|
|
})
|
|
return services.NewAdminService(st, mapSvc), st
|
|
}
|
|
|
|
func TestListUsers_Empty(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
users, err := admin.ListUsers(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(users) != 0 {
|
|
t.Fatalf("expected 0 users, got %d", len(users))
|
|
}
|
|
}
|
|
|
|
func TestListUsers_WithUsers(t *testing.T) {
|
|
admin, st := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
createUser(t, st, "alice", "pass", nil)
|
|
createUser(t, st, "bob", "pass", nil)
|
|
|
|
users, err := admin.ListUsers(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(users) != 2 {
|
|
t.Fatalf("expected 2 users, got %d", len(users))
|
|
}
|
|
}
|
|
|
|
func TestAdminGetUser_Found(t *testing.T) {
|
|
admin, st := newTestAdmin(t)
|
|
createUser(t, st, "alice", "pass", app.Auths{app.AUTH_MAP, app.AUTH_UPLOAD})
|
|
|
|
auths, found := admin.GetUser(context.Background(), "alice")
|
|
if !found {
|
|
t.Fatal("expected found")
|
|
}
|
|
if !auths.Has(app.AUTH_MAP) {
|
|
t.Fatal("expected map auth")
|
|
}
|
|
}
|
|
|
|
func TestAdminGetUser_NotFound(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
_, found := admin.GetUser(context.Background(), "ghost")
|
|
if found {
|
|
t.Fatal("expected not found")
|
|
}
|
|
}
|
|
|
|
func TestCreateOrUpdateUser_New(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
|
|
_, err := admin.CreateOrUpdateUser(ctx, "bob", "secret", app.Auths{app.AUTH_MAP})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
auths, found := admin.GetUser(ctx, "bob")
|
|
if !found {
|
|
t.Fatal("expected user to exist")
|
|
}
|
|
if !auths.Has(app.AUTH_MAP) {
|
|
t.Fatal("expected map auth")
|
|
}
|
|
}
|
|
|
|
func TestCreateOrUpdateUser_Update(t *testing.T) {
|
|
admin, st := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
createUser(t, st, "alice", "old", app.Auths{app.AUTH_MAP})
|
|
|
|
_, err := admin.CreateOrUpdateUser(ctx, "alice", "new", app.Auths{app.AUTH_ADMIN, app.AUTH_MAP})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
auths, found := admin.GetUser(ctx, "alice")
|
|
if !found {
|
|
t.Fatal("expected user")
|
|
}
|
|
if !auths.Has(app.AUTH_ADMIN) {
|
|
t.Fatal("expected admin auth after update")
|
|
}
|
|
}
|
|
|
|
func TestCreateOrUpdateUser_AdminBootstrap(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
|
|
adminCreated, err := admin.CreateOrUpdateUser(ctx, "admin", "pass", app.Auths{app.AUTH_ADMIN})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !adminCreated {
|
|
t.Fatal("expected adminCreated=true for new admin user")
|
|
}
|
|
|
|
adminCreated, err = admin.CreateOrUpdateUser(ctx, "admin", "pass2", app.Auths{app.AUTH_ADMIN})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if adminCreated {
|
|
t.Fatal("expected adminCreated=false for existing admin user")
|
|
}
|
|
}
|
|
|
|
func TestDeleteUser(t *testing.T) {
|
|
admin, st := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
createUser(t, st, "alice", "pass", app.Auths{app.AUTH_UPLOAD})
|
|
|
|
auth := services.NewAuthService(st)
|
|
auth.GenerateTokenForUser(ctx, "alice")
|
|
|
|
if err := admin.DeleteUser(ctx, "alice"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, found := admin.GetUser(ctx, "alice")
|
|
if found {
|
|
t.Fatal("expected user to be deleted")
|
|
}
|
|
}
|
|
|
|
func TestGetSettings_Defaults(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
prefix, defaultHide, title, err := admin.GetSettings(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if prefix != "" || defaultHide || title != "" {
|
|
t.Fatalf("expected empty defaults, got prefix=%q defaultHide=%v title=%q", prefix, defaultHide, title)
|
|
}
|
|
}
|
|
|
|
func TestUpdateSettings(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
|
|
p := "pfx"
|
|
dh := true
|
|
ti := "My Map"
|
|
if err := admin.UpdateSettings(ctx, &p, &dh, &ti); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
prefix, defaultHide, title, err := admin.GetSettings(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if prefix != "pfx" {
|
|
t.Fatalf("expected pfx, got %s", prefix)
|
|
}
|
|
if !defaultHide {
|
|
t.Fatal("expected defaultHide=true")
|
|
}
|
|
if title != "My Map" {
|
|
t.Fatalf("expected My Map, got %s", title)
|
|
}
|
|
|
|
dh2 := false
|
|
if err := admin.UpdateSettings(ctx, nil, &dh2, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, defaultHide2, _, _ := admin.GetSettings(ctx)
|
|
if defaultHide2 {
|
|
t.Fatal("expected defaultHide=false after update")
|
|
}
|
|
}
|
|
|
|
func TestListMaps_Empty(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
maps, err := admin.ListMaps(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(maps) != 0 {
|
|
t.Fatalf("expected 0 maps, got %d", len(maps))
|
|
}
|
|
}
|
|
|
|
func TestMapCRUD(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
|
|
if err := admin.UpdateMap(ctx, 1, "world", false, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mi, found := admin.GetMap(ctx, 1)
|
|
if !found || mi == nil {
|
|
t.Fatal("expected map")
|
|
}
|
|
if mi.Name != "world" {
|
|
t.Fatalf("expected world, got %s", mi.Name)
|
|
}
|
|
|
|
maps, err := admin.ListMaps(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(maps) != 1 {
|
|
t.Fatalf("expected 1 map, got %d", len(maps))
|
|
}
|
|
}
|
|
|
|
func TestToggleMapHidden(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
|
|
admin.UpdateMap(ctx, 1, "world", false, false)
|
|
|
|
mi, err := admin.ToggleMapHidden(ctx, 1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !mi.Hidden {
|
|
t.Fatal("expected hidden=true after toggle")
|
|
}
|
|
|
|
mi, err = admin.ToggleMapHidden(ctx, 1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if mi.Hidden {
|
|
t.Fatal("expected hidden=false after second toggle")
|
|
}
|
|
}
|
|
|
|
func TestWipe(t *testing.T) {
|
|
admin, st := newTestAdmin(t)
|
|
ctx := context.Background()
|
|
|
|
st.Update(ctx, func(tx *bbolt.Tx) error {
|
|
st.PutGrid(tx, "g1", []byte("data"))
|
|
st.PutMap(tx, 1, []byte("data"))
|
|
st.PutTile(tx, 1, 0, "0_0", []byte("data"))
|
|
st.CreateMarkersBuckets(tx)
|
|
return nil
|
|
})
|
|
|
|
if err := admin.Wipe(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
st.View(ctx, func(tx *bbolt.Tx) error {
|
|
if st.GetGrid(tx, "g1") != nil {
|
|
t.Fatal("expected grids wiped")
|
|
}
|
|
if st.GetMap(tx, 1) != nil {
|
|
t.Fatal("expected maps wiped")
|
|
}
|
|
if st.GetTile(tx, 1, 0, "0_0") != nil {
|
|
t.Fatal("expected tiles wiped")
|
|
}
|
|
if st.GetMarkersGridBucket(tx) != nil {
|
|
t.Fatal("expected markers wiped")
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestGetMap_NotFound(t *testing.T) {
|
|
admin, _ := newTestAdmin(t)
|
|
_, found := admin.GetMap(context.Background(), 999)
|
|
if found {
|
|
t.Fatal("expected not found")
|
|
}
|
|
}
|