Refactor Docker and Makefile configurations for improved build processes
- Updated docker-compose.tools.yml to mount source code at /src and set working directory for backend tools, ensuring proper Go module caching. - Modified Dockerfile.tools to install the latest golangci-lint version compatible with Go 1.24 and adjusted working directory for build-time operations. - Enhanced Makefile to build backend tools before running tests and linting, ensuring dependencies are up-to-date and improving overall workflow efficiency. - Refactored test and handler files to include error handling for database operations, enhancing reliability and debugging capabilities.
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
# Backend tools image: Go + golangci-lint for test, fmt, lint.
|
# Backend tools image: Go + golangci-lint for test, fmt, lint.
|
||||||
# Source is mounted at /hnh-map at run time via docker-compose.tools.yml.
|
# Source is mounted at /src at run time; this WORKDIR is only for build-time go mod download.
|
||||||
FROM golang:1.24-alpine
|
FROM golang:1.24-alpine
|
||||||
|
|
||||||
RUN go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.61.0
|
# v1.64+ required for Go 1.24 (export data format); see https://github.com/golangci/golangci-lint/issues/5225
|
||||||
|
RUN go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.0
|
||||||
|
|
||||||
WORKDIR /hnh-map
|
WORKDIR /build
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -11,17 +11,23 @@ build:
|
|||||||
test: test-backend test-frontend
|
test: test-backend test-frontend
|
||||||
|
|
||||||
test-backend:
|
test-backend:
|
||||||
$(TOOLS_COMPOSE) run --rm backend-tools go test ./...
|
$(TOOLS_COMPOSE) build backend-tools
|
||||||
|
$(TOOLS_COMPOSE) run --rm backend-tools sh -c "go mod download && go test ./..."
|
||||||
|
|
||||||
test-frontend:
|
test-frontend:
|
||||||
|
$(TOOLS_COMPOSE) build frontend-tools
|
||||||
$(TOOLS_COMPOSE) run --rm frontend-tools sh -c "npm ci && npm test"
|
$(TOOLS_COMPOSE) run --rm frontend-tools sh -c "npm ci && npm test"
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
$(TOOLS_COMPOSE) run --rm backend-tools golangci-lint run
|
$(TOOLS_COMPOSE) build backend-tools
|
||||||
|
$(TOOLS_COMPOSE) build frontend-tools
|
||||||
|
$(TOOLS_COMPOSE) run --rm backend-tools sh -c "go mod download && golangci-lint run"
|
||||||
$(TOOLS_COMPOSE) run --rm frontend-tools sh -c "npm ci && npm run lint"
|
$(TOOLS_COMPOSE) run --rm frontend-tools sh -c "npm ci && npm run lint"
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
$(TOOLS_COMPOSE) run --rm backend-tools go fmt ./...
|
$(TOOLS_COMPOSE) build backend-tools
|
||||||
|
$(TOOLS_COMPOSE) build frontend-tools
|
||||||
|
$(TOOLS_COMPOSE) run --rm backend-tools sh -c "go mod download && go fmt ./..."
|
||||||
$(TOOLS_COMPOSE) run --rm frontend-tools sh -c "npm ci && npm run format"
|
$(TOOLS_COMPOSE) run --rm frontend-tools sh -c "npm ci && npm run format"
|
||||||
|
|
||||||
generate-frontend:
|
generate-frontend:
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
# One-off tools: test, lint, fmt. Use with: docker compose -f docker-compose.tools.yml run --rm <service> <cmd>
|
# One-off tools: test, lint, fmt. Use with: docker compose -f docker-compose.tools.yml run --rm <service> <cmd>
|
||||||
# Source is mounted so commands run against current code.
|
# Source is mounted so commands run against current code.
|
||||||
|
# Backend: mount at /src so the image's /go module cache (from build) is not overwritten.
|
||||||
|
|
||||||
services:
|
services:
|
||||||
backend-tools:
|
backend-tools:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.tools
|
dockerfile: Dockerfile.tools
|
||||||
|
working_dir: /src
|
||||||
|
environment:
|
||||||
|
GOPATH: /go
|
||||||
|
GOMODCACHE: /go/pkg/mod
|
||||||
volumes:
|
volumes:
|
||||||
- .:/hnh-map
|
- .:/src
|
||||||
# Default command; override when running (e.g. go test ./..., golangci-lint run).
|
# Default command; override when running (e.g. go test ./..., golangci-lint run).
|
||||||
command: ["go", "test", "./..."]
|
command: ["go", "test", "./..."]
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||||
|
|
||||||
export default withNuxt({
|
export default withNuxt(
|
||||||
rules: {
|
{ ignores: ['eslint.config.mjs'] },
|
||||||
'@typescript-eslint/no-explicit-any': 'warn',
|
{
|
||||||
'@typescript-eslint/no-unused-vars': 'warn',
|
rules: {
|
||||||
'@typescript-eslint/consistent-type-imports': ['warn', { prefer: 'type-imports' }],
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
'@typescript-eslint/no-require-imports': 'off',
|
'@typescript-eslint/no-unused-vars': 'warn',
|
||||||
|
'@typescript-eslint/consistent-type-imports': ['warn', { prefer: 'type-imports' }],
|
||||||
|
'@typescript-eslint/no-require-imports': 'off',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ func (h *Handlers) clientLocate(rw http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
rw.Header().Set("Content-Type", "text/plain")
|
rw.Header().Set("Content-Type", "text/plain")
|
||||||
rw.WriteHeader(http.StatusOK)
|
rw.WriteHeader(http.StatusOK)
|
||||||
rw.Write([]byte(result))
|
_, _ = rw.Write([]byte(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) clientGridUpdate(rw http.ResponseWriter, req *http.Request) {
|
func (h *Handlers) clientGridUpdate(rw http.ResponseWriter, req *http.Request) {
|
||||||
@@ -85,7 +85,7 @@ func (h *Handlers) clientGridUpdate(rw http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
rw.Header().Set("Content-Type", "application/json")
|
||||||
rw.WriteHeader(http.StatusOK)
|
rw.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(rw).Encode(result.Response)
|
_ = json.NewEncoder(rw).Encode(result.Response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handlers) clientGridUpload(rw http.ResponseWriter, req *http.Request) {
|
func (h *Handlers) clientGridUpload(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|||||||
@@ -64,9 +64,11 @@ func (env *testEnv) createUser(t *testing.T, username, password string, auths ap
|
|||||||
hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost)
|
hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost)
|
||||||
u := app.User{Pass: hash, Auths: auths}
|
u := app.User{Pass: hash, Auths: auths}
|
||||||
raw, _ := json.Marshal(u)
|
raw, _ := json.Marshal(u)
|
||||||
env.st.Update(context.Background(), func(tx *bbolt.Tx) error {
|
if err := env.st.Update(context.Background(), func(tx *bbolt.Tx) error {
|
||||||
return env.st.PutUser(tx, username, raw)
|
return env.st.PutUser(tx, username, raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *testEnv) loginSession(t *testing.T, username string) string {
|
func (env *testEnv) loginSession(t *testing.T, username string) string {
|
||||||
@@ -90,7 +92,7 @@ func TestAPISetup_NoUsers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp struct{ SetupRequired bool }
|
var resp struct{ SetupRequired bool }
|
||||||
json.NewDecoder(rr.Body).Decode(&resp)
|
_ = json.NewDecoder(rr.Body).Decode(&resp)
|
||||||
if !resp.SetupRequired {
|
if !resp.SetupRequired {
|
||||||
t.Fatal("expected setupRequired=true")
|
t.Fatal("expected setupRequired=true")
|
||||||
}
|
}
|
||||||
@@ -105,7 +107,7 @@ func TestAPISetup_WithUsers(t *testing.T) {
|
|||||||
env.h.APISetup(rr, req)
|
env.h.APISetup(rr, req)
|
||||||
|
|
||||||
var resp struct{ SetupRequired bool }
|
var resp struct{ SetupRequired bool }
|
||||||
json.NewDecoder(rr.Body).Decode(&resp)
|
_ = json.NewDecoder(rr.Body).Decode(&resp)
|
||||||
if resp.SetupRequired {
|
if resp.SetupRequired {
|
||||||
t.Fatal("expected setupRequired=false with users")
|
t.Fatal("expected setupRequired=false with users")
|
||||||
}
|
}
|
||||||
@@ -196,7 +198,7 @@ func TestAPIMe_Authenticated(t *testing.T) {
|
|||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Auths []string `json:"auths"`
|
Auths []string `json:"auths"`
|
||||||
}
|
}
|
||||||
json.NewDecoder(rr.Body).Decode(&resp)
|
_ = json.NewDecoder(rr.Body).Decode(&resp)
|
||||||
if resp.Username != "alice" {
|
if resp.Username != "alice" {
|
||||||
t.Fatalf("expected alice, got %s", resp.Username)
|
t.Fatalf("expected alice, got %s", resp.Username)
|
||||||
}
|
}
|
||||||
@@ -245,7 +247,7 @@ func TestAPIMeTokens_Authenticated(t *testing.T) {
|
|||||||
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
|
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
|
||||||
}
|
}
|
||||||
var resp struct{ Tokens []string }
|
var resp struct{ Tokens []string }
|
||||||
json.NewDecoder(rr.Body).Decode(&resp)
|
_ = json.NewDecoder(rr.Body).Decode(&resp)
|
||||||
if len(resp.Tokens) != 1 {
|
if len(resp.Tokens) != 1 {
|
||||||
t.Fatalf("expected 1 token, got %d", len(resp.Tokens))
|
t.Fatalf("expected 1 token, got %d", len(resp.Tokens))
|
||||||
}
|
}
|
||||||
@@ -396,7 +398,7 @@ func TestAdminSettings(t *testing.T) {
|
|||||||
DefaultHide bool `json:"defaultHide"`
|
DefaultHide bool `json:"defaultHide"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
}
|
}
|
||||||
json.NewDecoder(rr3.Body).Decode(&resp)
|
_ = json.NewDecoder(rr3.Body).Decode(&resp)
|
||||||
if resp.Prefix != "pfx" || !resp.DefaultHide || resp.Title != "New Title" {
|
if resp.Prefix != "pfx" || !resp.DefaultHide || resp.Title != "New Title" {
|
||||||
t.Fatalf("unexpected settings: %+v", resp)
|
t.Fatalf("unexpected settings: %+v", resp)
|
||||||
}
|
}
|
||||||
@@ -493,7 +495,7 @@ func TestAPIGetChars_NoMarkersAuth(t *testing.T) {
|
|||||||
t.Fatalf("expected 200, got %d", rr.Code)
|
t.Fatalf("expected 200, got %d", rr.Code)
|
||||||
}
|
}
|
||||||
var chars []interface{}
|
var chars []interface{}
|
||||||
json.NewDecoder(rr.Body).Decode(&chars)
|
_ = json.NewDecoder(rr.Body).Decode(&chars)
|
||||||
if len(chars) != 0 {
|
if len(chars) != 0 {
|
||||||
t.Fatal("expected empty array without markers auth")
|
t.Fatal("expected empty array without markers auth")
|
||||||
}
|
}
|
||||||
@@ -511,7 +513,7 @@ func TestAPIGetMarkers_NoMarkersAuth(t *testing.T) {
|
|||||||
t.Fatalf("expected 200, got %d", rr.Code)
|
t.Fatalf("expected 200, got %d", rr.Code)
|
||||||
}
|
}
|
||||||
var markers []interface{}
|
var markers []interface{}
|
||||||
json.NewDecoder(rr.Body).Decode(&markers)
|
_ = json.NewDecoder(rr.Body).Decode(&markers)
|
||||||
if len(markers) != 0 {
|
if len(markers) != 0 {
|
||||||
t.Fatal("expected empty array without markers auth")
|
t.Fatal("expected empty array without markers auth")
|
||||||
}
|
}
|
||||||
@@ -583,7 +585,7 @@ func TestAdminUserByName(t *testing.T) {
|
|||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Auths []string `json:"auths"`
|
Auths []string `json:"auths"`
|
||||||
}
|
}
|
||||||
json.NewDecoder(rr.Body).Decode(&resp)
|
_ = json.NewDecoder(rr.Body).Decode(&resp)
|
||||||
if resp.Username != "bob" {
|
if resp.Username != "bob" {
|
||||||
t.Fatalf("expected bob, got %s", resp.Username)
|
t.Fatalf("expected bob, got %s", resp.Username)
|
||||||
}
|
}
|
||||||
@@ -613,9 +615,11 @@ func TestClientRouter_Locate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 2, Y: 3}}
|
gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 2, Y: 3}}
|
||||||
raw, _ := json.Marshal(gd)
|
raw, _ := json.Marshal(gd)
|
||||||
env.st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := env.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return env.st.PutGrid(tx, "g1", raw)
|
return env.st.PutGrid(tx, "g1", raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/client/"+tokens[0]+"/locate?gridID=g1", nil)
|
req := httptest.NewRequest(http.MethodGet, "/client/"+tokens[0]+"/locate?gridID=g1", nil)
|
||||||
rr := httptest.NewRecorder()
|
rr := httptest.NewRecorder()
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (h *Handlers) WatchGridUpdates(rw http.ResponseWriter, req *http.Request) {
|
|||||||
tileCache := []services.TileCache{}
|
tileCache := []services.TileCache{}
|
||||||
raw, _ := json.Marshal(tileCache)
|
raw, _ := json.Marshal(tileCache)
|
||||||
fmt.Fprint(rw, "data: ")
|
fmt.Fprint(rw, "data: ")
|
||||||
rw.Write(raw)
|
_, _ = rw.Write(raw)
|
||||||
fmt.Fprint(rw, "\n\n")
|
fmt.Fprint(rw, "\n\n")
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
|
|
||||||
@@ -93,13 +93,13 @@ func (h *Handlers) WatchGridUpdates(rw http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
fmt.Fprint(rw, "event: merge\n")
|
fmt.Fprint(rw, "event: merge\n")
|
||||||
fmt.Fprint(rw, "data: ")
|
fmt.Fprint(rw, "data: ")
|
||||||
rw.Write(raw)
|
_, _ = rw.Write(raw)
|
||||||
fmt.Fprint(rw, "\n\n")
|
fmt.Fprint(rw, "\n\n")
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
raw, _ := json.Marshal(tileCache)
|
raw, _ := json.Marshal(tileCache)
|
||||||
fmt.Fprint(rw, "data: ")
|
fmt.Fprint(rw, "data: ")
|
||||||
rw.Write(raw)
|
_, _ = rw.Write(raw)
|
||||||
fmt.Fprint(rw, "\n\n")
|
fmt.Fprint(rw, "\n\n")
|
||||||
tileCache = tileCache[:0]
|
tileCache = tileCache[:0]
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
@@ -152,7 +152,7 @@ func (h *Handlers) GridTile(rw http.ResponseWriter, req *http.Request) {
|
|||||||
rw.Header().Set("Content-Type", "image/png")
|
rw.Header().Set("Content-Type", "image/png")
|
||||||
rw.Header().Set("Cache-Control", "private, max-age=3600")
|
rw.Header().Set("Cache-Control", "private, max-age=3600")
|
||||||
rw.WriteHeader(http.StatusOK)
|
rw.WriteHeader(http.StatusOK)
|
||||||
rw.Write(transparentPNG)
|
_, _ = rw.Write(transparentPNG)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,9 @@ var migrations = []func(tx *bbolt.Tx) error{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
users.Put(k, raw)
|
if err := users.Put(k, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func TestRunMigrations_FreshDB(t *testing.T) {
|
|||||||
t.Fatalf("migrations failed on fresh DB: %v", err)
|
t.Fatalf("migrations failed on fresh DB: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.View(func(tx *bbolt.Tx) error {
|
if err := db.View(func(tx *bbolt.Tx) error {
|
||||||
b := tx.Bucket(store.BucketConfig)
|
b := tx.Bucket(store.BucketConfig)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
t.Fatal("expected config bucket after migrations")
|
t.Fatal("expected config bucket after migrations")
|
||||||
@@ -40,13 +40,15 @@ func TestRunMigrations_FreshDB(t *testing.T) {
|
|||||||
t.Fatalf("expected default title, got %s", title)
|
t.Fatalf("expected default title, got %s", title)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if tx, _ := db.Begin(false); tx != nil {
|
if tx, _ := db.Begin(false); tx != nil {
|
||||||
if tx.Bucket(store.BucketOAuthStates) == nil {
|
if tx.Bucket(store.BucketOAuthStates) == nil {
|
||||||
t.Fatal("expected oauth_states bucket after migrations")
|
t.Fatal("expected oauth_states bucket after migrations")
|
||||||
}
|
}
|
||||||
tx.Rollback()
|
_ = tx.Rollback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +63,7 @@ func TestRunMigrations_Idempotent(t *testing.T) {
|
|||||||
t.Fatalf("second run failed: %v", err)
|
t.Fatalf("second run failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.View(func(tx *bbolt.Tx) error {
|
if err := db.View(func(tx *bbolt.Tx) error {
|
||||||
b := tx.Bucket(store.BucketConfig)
|
b := tx.Bucket(store.BucketConfig)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
t.Fatal("expected config bucket")
|
t.Fatal("expected config bucket")
|
||||||
@@ -71,7 +73,9 @@ func TestRunMigrations_Idempotent(t *testing.T) {
|
|||||||
t.Fatal("expected version key")
|
t.Fatal("expected version key")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunMigrations_SetsVersion(t *testing.T) {
|
func TestRunMigrations_SetsVersion(t *testing.T) {
|
||||||
@@ -81,11 +85,13 @@ func TestRunMigrations_SetsVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var version string
|
var version string
|
||||||
db.View(func(tx *bbolt.Tx) error {
|
if err := db.View(func(tx *bbolt.Tx) error {
|
||||||
b := tx.Bucket(store.BucketConfig)
|
b := tx.Bucket(store.BucketConfig)
|
||||||
version = string(b.Get([]byte("version")))
|
version = string(b.Get([]byte("version")))
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if version == "" || version == "0" {
|
if version == "" || version == "0" {
|
||||||
t.Fatalf("expected non-zero version, got %q", version)
|
t.Fatalf("expected non-zero version, got %q", version)
|
||||||
|
|||||||
@@ -101,7 +101,9 @@ func (s *AdminService) DeleteUser(ctx context.Context, username string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, tok := range u.Tokens {
|
for _, tok := range u.Tokens {
|
||||||
s.st.DeleteToken(tx, tok)
|
if err := s.st.DeleteToken(tx, tok); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.st.DeleteUser(tx, username)
|
return s.st.DeleteUser(tx, username)
|
||||||
@@ -129,17 +131,25 @@ func (s *AdminService) GetSettings(ctx context.Context) (prefix string, defaultH
|
|||||||
func (s *AdminService) UpdateSettings(ctx context.Context, prefix *string, defaultHide *bool, title *string) error {
|
func (s *AdminService) UpdateSettings(ctx context.Context, prefix *string, defaultHide *bool, title *string) error {
|
||||||
return s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
return s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
if prefix != nil {
|
if prefix != nil {
|
||||||
s.st.PutConfig(tx, "prefix", []byte(*prefix))
|
if err := s.st.PutConfig(tx, "prefix", []byte(*prefix)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if defaultHide != nil {
|
if defaultHide != nil {
|
||||||
if *defaultHide {
|
if *defaultHide {
|
||||||
s.st.PutConfig(tx, "defaultHide", []byte("1"))
|
if err := s.st.PutConfig(tx, "defaultHide", []byte("1")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
s.st.DeleteConfig(tx, "defaultHide")
|
if err := s.st.DeleteConfig(tx, "defaultHide"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if title != nil {
|
if title != nil {
|
||||||
s.st.PutConfig(tx, "title", []byte(*title))
|
if err := s.st.PutConfig(tx, "title", []byte(*title)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -264,7 +274,9 @@ func (s *AdminService) WipeTile(ctx context.Context, mapid, x, y int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
grids.Delete(id)
|
if err := grids.Delete(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -310,7 +322,9 @@ func (s *AdminService) SetCoords(ctx context.Context, mapid, fx, fy, tx2, ty int
|
|||||||
g.Coord.X += diff.X
|
g.Coord.X += diff.X
|
||||||
g.Coord.Y += diff.Y
|
g.Coord.Y += diff.Y
|
||||||
raw, _ := json.Marshal(g)
|
raw, _ := json.Marshal(g)
|
||||||
grids.Put(k, raw)
|
if err := grids.Put(k, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -367,7 +381,9 @@ func (s *AdminService) HideMarker(ctx context.Context, markerID string) error {
|
|||||||
}
|
}
|
||||||
m.Hidden = true
|
m.Hidden = true
|
||||||
raw, _ = json.Marshal(m)
|
raw, _ = json.Marshal(m)
|
||||||
grid.Put(key, raw)
|
if err := grid.Put(key, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ func TestToggleMapHidden(t *testing.T) {
|
|||||||
admin, _ := newTestAdmin(t)
|
admin, _ := newTestAdmin(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
admin.UpdateMap(ctx, 1, "world", false, false)
|
_ = admin.UpdateMap(ctx, 1, "world", false, false)
|
||||||
|
|
||||||
mi, err := admin.ToggleMapHidden(ctx, 1)
|
mi, err := admin.ToggleMapHidden(ctx, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -257,19 +257,27 @@ func TestWipe(t *testing.T) {
|
|||||||
admin, st := newTestAdmin(t)
|
admin, st := newTestAdmin(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
st.PutGrid(tx, "g1", []byte("data"))
|
if err := st.PutGrid(tx, "g1", []byte("data")); err != nil {
|
||||||
st.PutMap(tx, 1, []byte("data"))
|
return err
|
||||||
st.PutTile(tx, 1, 0, "0_0", []byte("data"))
|
}
|
||||||
st.CreateMarkersBuckets(tx)
|
if err := st.PutMap(tx, 1, []byte("data")); err != nil {
|
||||||
return nil
|
return err
|
||||||
})
|
}
|
||||||
|
if err := st.PutTile(tx, 1, 0, "0_0", []byte("data")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _, err := st.CreateMarkersBuckets(tx)
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := admin.Wipe(ctx); err != nil {
|
if err := admin.Wipe(ctx); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
if st.GetGrid(tx, "g1") != nil {
|
if st.GetGrid(tx, "g1") != nil {
|
||||||
t.Fatal("expected grids wiped")
|
t.Fatal("expected grids wiped")
|
||||||
}
|
}
|
||||||
@@ -283,7 +291,9 @@ func TestWipe(t *testing.T) {
|
|||||||
t.Fatal("expected markers wiped")
|
t.Fatal("expected markers wiped")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetMap_NotFound(t *testing.T) {
|
func TestGetMap_NotFound(t *testing.T) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (s *AuthService) GetSession(ctx context.Context, req *http.Request) *app.Se
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var sess *app.Session
|
var sess *app.Session
|
||||||
s.st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := s.st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
raw := s.st.GetSession(tx, c.Value)
|
raw := s.st.GetSession(tx, c.Value)
|
||||||
if raw == nil {
|
if raw == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -77,7 +77,9 @@ func (s *AuthService) GetSession(ctx context.Context, req *http.Request) *app.Se
|
|||||||
}
|
}
|
||||||
sess.Auths = u.Auths
|
sess.Auths = u.Auths
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return sess
|
return sess
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +167,7 @@ func (s *AuthService) GetUserByUsername(ctx context.Context, username string) *a
|
|||||||
// SetupRequired returns true if no users exist (first run).
|
// SetupRequired returns true if no users exist (first run).
|
||||||
func (s *AuthService) SetupRequired(ctx context.Context) bool {
|
func (s *AuthService) SetupRequired(ctx context.Context) bool {
|
||||||
var required bool
|
var required bool
|
||||||
s.st.View(ctx, func(tx *bbolt.Tx) error {
|
_ = s.st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
if s.st.UserCount(tx) == 0 {
|
if s.st.UserCount(tx) == 0 {
|
||||||
required = true
|
required = true
|
||||||
}
|
}
|
||||||
@@ -181,7 +183,7 @@ func (s *AuthService) BootstrapAdmin(ctx context.Context, username, pass, bootst
|
|||||||
}
|
}
|
||||||
var created bool
|
var created bool
|
||||||
var u *app.User
|
var u *app.User
|
||||||
s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
if s.st.GetUser(tx, "admin") != nil {
|
if s.st.GetUser(tx, "admin") != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -200,7 +202,9 @@ func (s *AuthService) BootstrapAdmin(ctx context.Context, username, pass, bootst
|
|||||||
created = true
|
created = true
|
||||||
u = &user
|
u = &user
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if created {
|
if created {
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
@@ -239,7 +243,7 @@ func (s *AuthService) GenerateTokenForUser(ctx context.Context, username string)
|
|||||||
}
|
}
|
||||||
token := hex.EncodeToString(tokenRaw)
|
token := hex.EncodeToString(tokenRaw)
|
||||||
var tokens []string
|
var tokens []string
|
||||||
s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
_ = s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
uRaw := s.st.GetUser(tx, username)
|
uRaw := s.st.GetUser(tx, username)
|
||||||
u := app.User{}
|
u := app.User{}
|
||||||
if uRaw != nil {
|
if uRaw != nil {
|
||||||
@@ -250,7 +254,9 @@ func (s *AuthService) GenerateTokenForUser(ctx context.Context, username string)
|
|||||||
u.Tokens = append(u.Tokens, token)
|
u.Tokens = append(u.Tokens, token)
|
||||||
tokens = u.Tokens
|
tokens = u.Tokens
|
||||||
buf, _ := json.Marshal(u)
|
buf, _ := json.Marshal(u)
|
||||||
s.st.PutUser(tx, username, buf)
|
if err := s.st.PutUser(tx, username, buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return s.st.PutToken(tx, token, username)
|
return s.st.PutToken(tx, token, username)
|
||||||
})
|
})
|
||||||
return tokens
|
return tokens
|
||||||
@@ -522,7 +528,9 @@ func (s *AuthService) findOrCreateOAuthUser(ctx context.Context, provider, sub,
|
|||||||
user.Email = email
|
user.Email = email
|
||||||
}
|
}
|
||||||
raw, _ = json.Marshal(user)
|
raw, _ = json.Marshal(user)
|
||||||
s.st.PutUser(tx, username, raw)
|
if err := s.st.PutUser(tx, username, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,9 +41,11 @@ func createUser(t *testing.T, st *store.Store, username, password string, auths
|
|||||||
}
|
}
|
||||||
u := app.User{Pass: hash, Auths: auths}
|
u := app.User{Pass: hash, Auths: auths}
|
||||||
raw, _ := json.Marshal(u)
|
raw, _ := json.Marshal(u)
|
||||||
st.Update(context.Background(), func(tx *bbolt.Tx) error {
|
if err := st.Update(context.Background(), func(tx *bbolt.Tx) error {
|
||||||
return st.PutUser(tx, username, raw)
|
return st.PutUser(tx, username, raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetupRequired_EmptyDB(t *testing.T) {
|
func TestSetupRequired_EmptyDB(t *testing.T) {
|
||||||
@@ -246,9 +248,11 @@ func TestGetUserTokensAndPrefix(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
createUser(t, st, "alice", "pass", app.Auths{app.AUTH_UPLOAD})
|
createUser(t, st, "alice", "pass", app.Auths{app.AUTH_UPLOAD})
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutConfig(tx, "prefix", []byte("myprefix"))
|
return st.PutConfig(tx, "prefix", []byte("myprefix"))
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
auth.GenerateTokenForUser(ctx, "alice")
|
auth.GenerateTokenForUser(ctx, "alice")
|
||||||
tokens, prefix := auth.GetUserTokensAndPrefix(ctx, "alice")
|
tokens, prefix := auth.GetUserTokensAndPrefix(ctx, "alice")
|
||||||
@@ -288,9 +292,11 @@ func TestValidateClientToken_NoUploadPerm(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
createUser(t, st, "alice", "pass", app.Auths{app.AUTH_MAP})
|
createUser(t, st, "alice", "pass", app.Auths{app.AUTH_MAP})
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutToken(tx, "tok123", "alice")
|
return st.PutToken(tx, "tok123", "alice")
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
_, err := auth.ValidateClientToken(ctx, "tok123")
|
_, err := auth.ValidateClientToken(ctx, "tok123")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -141,7 +141,9 @@ func (s *ClientService) ProcessGridUpdate(ctx context.Context, grup GridUpdate)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
grids.Put([]byte(grid), raw)
|
if err := grids.Put([]byte(grid), raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
greq.GridRequests = append(greq.GridRequests, grid)
|
greq.GridRequests = append(greq.GridRequests, grid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +194,9 @@ func (s *ClientService) ProcessGridUpdate(ctx context.Context, grup GridUpdate)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
grids.Put([]byte(grid), raw)
|
if err := grids.Put([]byte(grid), raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
greq.GridRequests = append(greq.GridRequests, grid)
|
greq.GridRequests = append(greq.GridRequests, grid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +211,7 @@ func (s *ClientService) ProcessGridUpdate(ctx context.Context, grup GridUpdate)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(maps) > 1 {
|
if len(maps) > 1 {
|
||||||
grids.ForEach(func(k, v []byte) error {
|
if err := grids.ForEach(func(k, v []byte) error {
|
||||||
gd := app.GridData{}
|
gd := app.GridData{}
|
||||||
if err := json.Unmarshal(v, &gd); err != nil {
|
if err := json.Unmarshal(v, &gd); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -244,16 +248,22 @@ func (s *ClientService) ProcessGridUpdate(ctx context.Context, grup GridUpdate)
|
|||||||
File: td.File,
|
File: td.File,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
grids.Put(k, raw)
|
if err := grids.Put(k, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for mergeid, merge := range maps {
|
for mergeid, merge := range maps {
|
||||||
if mapid == mergeid {
|
if mapid == mergeid {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mapB.Delete([]byte(strconv.Itoa(mergeid)))
|
if err := mapB.Delete([]byte(strconv.Itoa(mergeid))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
slog.Info("reporting merge", "from", mergeid, "to", mapid)
|
slog.Info("reporting merge", "from", mergeid, "to", mapid)
|
||||||
s.mapSvc.ReportMerge(mergeid, mapid, app.Coord{X: offset.X - merge.X, Y: offset.Y - merge.Y})
|
s.mapSvc.ReportMerge(mergeid, mapid, app.Coord{X: offset.X - merge.X, Y: offset.Y - merge.Y})
|
||||||
}
|
}
|
||||||
@@ -271,10 +281,10 @@ func (s *ClientService) ProcessGridUpdate(ctx context.Context, grup GridUpdate)
|
|||||||
func (s *ClientService) ProcessGridUpload(ctx context.Context, id string, extraData string, fileReader io.Reader) error {
|
func (s *ClientService) ProcessGridUpload(ctx context.Context, id string, extraData string, fileReader io.Reader) error {
|
||||||
if extraData != "" {
|
if extraData != "" {
|
||||||
ed := ExtraData{}
|
ed := ExtraData{}
|
||||||
json.Unmarshal([]byte(extraData), &ed)
|
_ = json.Unmarshal([]byte(extraData), &ed)
|
||||||
if ed.Season == 3 {
|
if ed.Season == 3 {
|
||||||
needTile := false
|
needTile := false
|
||||||
s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
raw := s.st.GetGrid(tx, id)
|
raw := s.st.GetGrid(tx, id)
|
||||||
if raw == nil {
|
if raw == nil {
|
||||||
return fmt.Errorf("unknown grid id: %s", id)
|
return fmt.Errorf("unknown grid id: %s", id)
|
||||||
@@ -301,7 +311,9 @@ func (s *ClientService) ProcessGridUpload(ctx context.Context, id string, extraD
|
|||||||
}
|
}
|
||||||
raw, _ = json.Marshal(cur)
|
raw, _ = json.Marshal(cur)
|
||||||
return s.st.PutGrid(tx, id, raw)
|
return s.st.PutGrid(tx, id, raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if !needTile {
|
if !needTile {
|
||||||
slog.Debug("ignoring tile upload: winter")
|
slog.Debug("ignoring tile upload: winter")
|
||||||
return nil
|
return nil
|
||||||
@@ -316,7 +328,7 @@ func (s *ClientService) ProcessGridUpload(ctx context.Context, id string, extraD
|
|||||||
cur := app.GridData{}
|
cur := app.GridData{}
|
||||||
mapid := 0
|
mapid := 0
|
||||||
|
|
||||||
s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
raw := s.st.GetGrid(tx, id)
|
raw := s.st.GetGrid(tx, id)
|
||||||
if raw == nil {
|
if raw == nil {
|
||||||
return fmt.Errorf("unknown grid id: %s", id)
|
return fmt.Errorf("unknown grid id: %s", id)
|
||||||
@@ -331,7 +343,9 @@ func (s *ClientService) ProcessGridUpload(ctx context.Context, id string, extraD
|
|||||||
}
|
}
|
||||||
raw, _ = json.Marshal(cur)
|
raw, _ = json.Marshal(cur)
|
||||||
return s.st.PutGrid(tx, id, raw)
|
return s.st.PutGrid(tx, id, raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if updateTile {
|
if updateTile {
|
||||||
gridDir := fmt.Sprintf("%s/grids", s.mapSvc.GridStorage())
|
gridDir := fmt.Sprintf("%s/grids", s.mapSvc.GridStorage())
|
||||||
@@ -374,7 +388,7 @@ func (s *ClientService) UpdatePositions(ctx context.Context, data []byte) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
gridDataByID := make(map[string]app.GridData)
|
gridDataByID := make(map[string]app.GridData)
|
||||||
s.st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := s.st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
for _, craw := range craws {
|
for _, craw := range craws {
|
||||||
raw := s.st.GetGrid(tx, craw.GridID)
|
raw := s.st.GetGrid(tx, craw.GridID)
|
||||||
if raw != nil {
|
if raw != nil {
|
||||||
@@ -385,7 +399,9 @@ func (s *ClientService) UpdatePositions(ctx context.Context, data []byte) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
username, _ := ctx.Value(app.ClientUsernameKey).(string)
|
username, _ := ctx.Value(app.ClientUsernameKey).(string)
|
||||||
|
|
||||||
@@ -478,8 +494,12 @@ func (s *ClientService) UploadMarkers(ctx context.Context, data []byte) error {
|
|||||||
Image: img,
|
Image: img,
|
||||||
}
|
}
|
||||||
raw, _ := json.Marshal(m)
|
raw, _ := json.Marshal(m)
|
||||||
grid.Put(key, raw)
|
if err := grid.Put(key, raw); err != nil {
|
||||||
idB.Put(idKey, key)
|
return err
|
||||||
|
}
|
||||||
|
if err := idB.Put(idKey, key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -58,9 +58,11 @@ func TestClientLocate_Found(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 2, Y: 3}}
|
gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 2, Y: 3}}
|
||||||
raw, _ := json.Marshal(gd)
|
raw, _ := json.Marshal(gd)
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutGrid(tx, "g1", raw)
|
return st.PutGrid(tx, "g1", raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
result, err := client.Locate(ctx, "g1")
|
result, err := client.Locate(ctx, "g1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
|||||||
if markersb != nil {
|
if markersb != nil {
|
||||||
markersgrid := markersb.Bucket(store.BucketMarkersGrid)
|
markersgrid := markersb.Bucket(store.BucketMarkersGrid)
|
||||||
if markersgrid != nil {
|
if markersgrid != nil {
|
||||||
markersgrid.ForEach(func(k, v []byte) error {
|
if err := markersgrid.ForEach(func(k, v []byte) error {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
@@ -125,7 +125,9 @@ func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
|||||||
maps[gridMap[marker.GridID]].Markers[marker.GridID] = append(maps[gridMap[marker.GridID]].Markers[marker.GridID], marker)
|
maps[gridMap[marker.GridID]].Markers[marker.GridID] = append(maps[gridMap[marker.GridID]].Markers[marker.GridID], marker)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -218,7 +220,11 @@ func (s *ExportService) Merge(ctx context.Context, zr *zip.Reader) error {
|
|||||||
f.Close()
|
f.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
io.Copy(f, r)
|
if _, err := io.Copy(f, r); err != nil {
|
||||||
|
r.Close()
|
||||||
|
f.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
r.Close()
|
r.Close()
|
||||||
f.Close()
|
f.Close()
|
||||||
newTiles[strings.TrimSuffix(filepath.Base(fhdr.Name), ".png")] = struct{}{}
|
newTiles[strings.TrimSuffix(filepath.Base(fhdr.Name), ".png")] = struct{}{}
|
||||||
@@ -290,8 +296,12 @@ func (s *ExportService) processMergeJSON(
|
|||||||
Image: img,
|
Image: img,
|
||||||
}
|
}
|
||||||
raw, _ := json.Marshal(m)
|
raw, _ := json.Marshal(m)
|
||||||
mgrid.Put(key, raw)
|
if err := mgrid.Put(key, raw); err != nil {
|
||||||
idB.Put(idKey, key)
|
return err
|
||||||
|
}
|
||||||
|
if err := idB.Put(idKey, key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +343,9 @@ func (s *ExportService) processMergeJSON(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
grids.Put([]byte(grid), raw)
|
if err := grids.Put([]byte(grid), raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -372,11 +384,13 @@ func (s *ExportService) processMergeJSON(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
grids.Put([]byte(grid), raw)
|
if err := grids.Put([]byte(grid), raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(existingMaps) > 1 {
|
if len(existingMaps) > 1 {
|
||||||
grids.ForEach(func(k, v []byte) error {
|
if err := grids.ForEach(func(k, v []byte) error {
|
||||||
gd := app.GridData{}
|
gd := app.GridData{}
|
||||||
if err := json.Unmarshal(v, &gd); err != nil {
|
if err := json.Unmarshal(v, &gd); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -413,16 +427,22 @@ func (s *ExportService) processMergeJSON(
|
|||||||
File: td.File,
|
File: td.File,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
grids.Put(k, raw)
|
if err := grids.Put(k, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for mergeid, merge := range existingMaps {
|
for mergeid, merge := range existingMaps {
|
||||||
if mapid == mergeid {
|
if mapid == mergeid {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mapB.Delete([]byte(strconv.Itoa(mergeid)))
|
if err := mapB.Delete([]byte(strconv.Itoa(mergeid))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
slog.Info("reporting merge", "from", mergeid, "to", mapid)
|
slog.Info("reporting merge", "from", mergeid, "to", mapid)
|
||||||
s.mapSvc.ReportMerge(mergeid, mapid, app.Coord{X: offset.X - merge.X, Y: offset.Y - merge.Y})
|
s.mapSvc.ReportMerge(mergeid, mapid, app.Coord{X: offset.X - merge.X, Y: offset.Y - merge.Y})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,14 @@ func TestExport_WithGrid(t *testing.T) {
|
|||||||
gdRaw, _ := json.Marshal(gd)
|
gdRaw, _ := json.Marshal(gd)
|
||||||
mi := app.MapInfo{ID: 1, Name: "test", Hidden: false}
|
mi := app.MapInfo{ID: 1, Name: "test", Hidden: false}
|
||||||
miRaw, _ := json.Marshal(mi)
|
miRaw, _ := json.Marshal(mi)
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
if err := st.PutGrid(tx, "g1", gdRaw); err != nil {
|
if err := st.PutGrid(tx, "g1", gdRaw); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return st.PutMap(tx, 1, miRaw)
|
return st.PutMap(tx, 1, miRaw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := export.Export(ctx, &buf)
|
err := export.Export(ctx, &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ func (s *MapService) getSubTiles(ctx context.Context, mapid int, c app.Coord, z
|
|||||||
|
|
||||||
// SaveTile persists a tile and broadcasts the update.
|
// SaveTile persists a tile and broadcasts the update.
|
||||||
func (s *MapService) SaveTile(ctx context.Context, mapid int, c app.Coord, z int, f string, t int64) {
|
func (s *MapService) SaveTile(ctx context.Context, mapid int, c app.Coord, z int, f string, t int64) {
|
||||||
s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
_ = s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
td := &app.TileData{
|
td := &app.TileData{
|
||||||
MapID: mapid,
|
MapID: mapid,
|
||||||
Coord: c,
|
Coord: c,
|
||||||
@@ -293,7 +293,7 @@ func (s *MapService) RebuildZooms(ctx context.Context) error {
|
|||||||
if b == nil {
|
if b == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
b.ForEach(func(k, v []byte) error {
|
if err := b.ForEach(func(k, v []byte) error {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
@@ -306,8 +306,12 @@ func (s *MapService) RebuildZooms(ctx context.Context) error {
|
|||||||
needProcess[zoomproc{grid.Coord.Parent(), grid.Map}] = struct{}{}
|
needProcess[zoomproc{grid.Coord.Parent(), grid.Map}] = struct{}{}
|
||||||
saveGrid[zoomproc{grid.Coord, grid.Map}] = grid.ID
|
saveGrid[zoomproc{grid.Coord, grid.Map}] = grid.ID
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
tx.DeleteBucket(store.BucketTiles)
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.DeleteBucket(store.BucketTiles); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
slog.Error("RebuildZooms: failed to update store", "error", err)
|
slog.Error("RebuildZooms: failed to update store", "error", err)
|
||||||
@@ -364,7 +368,7 @@ func (s *MapService) WatchMerges() chan *app.Merge {
|
|||||||
// GetAllTileCache returns all tiles for the initial SSE cache dump.
|
// GetAllTileCache returns all tiles for the initial SSE cache dump.
|
||||||
func (s *MapService) GetAllTileCache(ctx context.Context) []TileCache {
|
func (s *MapService) GetAllTileCache(ctx context.Context) []TileCache {
|
||||||
var cache []TileCache
|
var cache []TileCache
|
||||||
s.st.View(ctx, func(tx *bbolt.Tx) error {
|
_ = s.st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
return s.st.ForEachTile(tx, func(mapK, zoomK, coordK, v []byte) error {
|
return s.st.ForEachTile(tx, func(mapK, zoomK, coordK, v []byte) error {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
|||||||
@@ -57,9 +57,11 @@ func TestGetConfig(t *testing.T) {
|
|||||||
svc, st := newTestMapService(t)
|
svc, st := newTestMapService(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutConfig(tx, "title", []byte("Test Map"))
|
return st.PutConfig(tx, "title", []byte("Test Map"))
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
config, err := svc.GetConfig(ctx, app.Auths{app.AUTH_MAP})
|
config, err := svc.GetConfig(ctx, app.Auths{app.AUTH_MAP})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -93,9 +95,11 @@ func TestGetConfig_Empty(t *testing.T) {
|
|||||||
func TestGetPage(t *testing.T) {
|
func TestGetPage(t *testing.T) {
|
||||||
svc, st := newTestMapService(t)
|
svc, st := newTestMapService(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutConfig(tx, "title", []byte("Map Page"))
|
return st.PutConfig(tx, "title", []byte("Map Page"))
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
page, err := svc.GetPage(ctx)
|
page, err := svc.GetPage(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -112,9 +116,11 @@ func TestGetGrid(t *testing.T) {
|
|||||||
|
|
||||||
gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 5, Y: 10}}
|
gd := app.GridData{ID: "g1", Map: 1, Coord: app.Coord{X: 5, Y: 10}}
|
||||||
raw, _ := json.Marshal(gd)
|
raw, _ := json.Marshal(gd)
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutGrid(tx, "g1", raw)
|
return st.PutGrid(tx, "g1", raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
got, err := svc.GetGrid(ctx, "g1")
|
got, err := svc.GetGrid(ctx, "g1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -158,11 +164,17 @@ func TestGetMaps_HiddenFilter(t *testing.T) {
|
|||||||
mi2 := app.MapInfo{ID: 2, Name: "hidden", Hidden: true}
|
mi2 := app.MapInfo{ID: 2, Name: "hidden", Hidden: true}
|
||||||
raw1, _ := json.Marshal(mi1)
|
raw1, _ := json.Marshal(mi1)
|
||||||
raw2, _ := json.Marshal(mi2)
|
raw2, _ := json.Marshal(mi2)
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
st.PutMap(tx, 1, raw1)
|
if err := st.PutMap(tx, 1, raw1); err != nil {
|
||||||
st.PutMap(tx, 2, raw2)
|
return err
|
||||||
|
}
|
||||||
|
if err := st.PutMap(tx, 2, raw2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
maps, err := svc.GetMaps(ctx, false)
|
maps, err := svc.GetMaps(ctx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -201,14 +213,18 @@ func TestGetMarkers_WithData(t *testing.T) {
|
|||||||
m := app.Marker{Name: "Tower", ID: 1, GridID: "g1", Position: app.Position{X: 10, Y: 20}, Image: "gfx/terobjs/mm/tower"}
|
m := app.Marker{Name: "Tower", ID: 1, GridID: "g1", Position: app.Position{X: 10, Y: 20}, Image: "gfx/terobjs/mm/tower"}
|
||||||
mRaw, _ := json.Marshal(m)
|
mRaw, _ := json.Marshal(m)
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
st.PutGrid(tx, "g1", gdRaw)
|
if err := st.PutGrid(tx, "g1", gdRaw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
grid, _, err := st.CreateMarkersBuckets(tx)
|
grid, _, err := st.CreateMarkersBuckets(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return grid.Put([]byte("g1_10_20"), mRaw)
|
return grid.Put([]byte("g1_10_20"), mRaw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
markers, err := svc.GetMarkers(ctx)
|
markers, err := svc.GetMarkers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -233,9 +249,11 @@ func TestGetTile(t *testing.T) {
|
|||||||
|
|
||||||
td := app.TileData{MapID: 1, Coord: app.Coord{X: 0, Y: 0}, Zoom: 0, File: "grids/g1.png", Cache: 12345}
|
td := app.TileData{MapID: 1, Coord: app.Coord{X: 0, Y: 0}, Zoom: 0, File: "grids/g1.png", Cache: 12345}
|
||||||
raw, _ := json.Marshal(td)
|
raw, _ := json.Marshal(td)
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutTile(tx, 1, 0, "0_0", raw)
|
return st.PutTile(tx, 1, 0, "0_0", raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
got := svc.GetTile(ctx, 1, app.Coord{X: 0, Y: 0}, 0)
|
got := svc.GetTile(ctx, 1, app.Coord{X: 0, Y: 0}, 0)
|
||||||
if got == nil {
|
if got == nil {
|
||||||
@@ -287,9 +305,11 @@ func TestGetAllTileCache_WithData(t *testing.T) {
|
|||||||
|
|
||||||
td := app.TileData{MapID: 1, Coord: app.Coord{X: 1, Y: 2}, Zoom: 0, Cache: 999}
|
td := app.TileData{MapID: 1, Coord: app.Coord{X: 1, Y: 2}, Zoom: 0, Cache: 999}
|
||||||
raw, _ := json.Marshal(td)
|
raw, _ := json.Marshal(td)
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.PutTile(tx, 1, 0, "1_2", raw)
|
return st.PutTile(tx, 1, 0, "1_2", raw)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
cache := svc.GetAllTileCache(ctx)
|
cache := svc.GetAllTileCache(ctx)
|
||||||
if len(cache) != 1 {
|
if len(cache) != 1 {
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ func TestUserCRUD(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Verify user doesn't exist on empty DB.
|
// Verify user doesn't exist on empty DB.
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
if got := st.GetUser(tx, "alice"); got != nil {
|
if got := st.GetUser(tx, "alice"); got != nil {
|
||||||
t.Fatal("expected nil user before creation")
|
t.Fatal("expected nil user before creation")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Create user.
|
// Create user.
|
||||||
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
@@ -40,7 +42,7 @@ func TestUserCRUD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify user exists and count is correct (separate transaction for accurate Stats).
|
// Verify user exists and count is correct (separate transaction for accurate Stats).
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
got := st.GetUser(tx, "alice")
|
got := st.GetUser(tx, "alice")
|
||||||
if got == nil || string(got) != `{"pass":"hash"}` {
|
if got == nil || string(got) != `{"pass":"hash"}` {
|
||||||
t.Fatalf("expected user data, got %s", got)
|
t.Fatalf("expected user data, got %s", got)
|
||||||
@@ -49,7 +51,9 @@ func TestUserCRUD(t *testing.T) {
|
|||||||
t.Fatalf("expected 1 user, got %d", c)
|
t.Fatalf("expected 1 user, got %d", c)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Delete user.
|
// Delete user.
|
||||||
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
@@ -58,31 +62,41 @@ func TestUserCRUD(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
if got := st.GetUser(tx, "alice"); got != nil {
|
if got := st.GetUser(tx, "alice"); got != nil {
|
||||||
t.Fatal("expected nil user after deletion")
|
t.Fatal("expected nil user after deletion")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForEachUser(t *testing.T) {
|
func TestForEachUser(t *testing.T) {
|
||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
st.PutUser(tx, "alice", []byte("1"))
|
if err := st.PutUser(tx, "alice", []byte("1")); err != nil {
|
||||||
st.PutUser(tx, "bob", []byte("2"))
|
return err
|
||||||
|
}
|
||||||
|
if err := st.PutUser(tx, "bob", []byte("2")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
var names []string
|
var names []string
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.ForEachUser(tx, func(k, _ []byte) error {
|
return st.ForEachUser(tx, func(k, _ []byte) error {
|
||||||
names = append(names, string(k))
|
names = append(names, string(k))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
if len(names) != 2 {
|
if len(names) != 2 {
|
||||||
t.Fatalf("expected 2 users, got %d", len(names))
|
t.Fatalf("expected 2 users, got %d", len(names))
|
||||||
}
|
}
|
||||||
@@ -91,12 +105,14 @@ func TestForEachUser(t *testing.T) {
|
|||||||
func TestUserCountEmptyBucket(t *testing.T) {
|
func TestUserCountEmptyBucket(t *testing.T) {
|
||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
if c := st.UserCount(tx); c != 0 {
|
if c := st.UserCount(tx); c != 0 {
|
||||||
t.Fatalf("expected 0 users on empty db, got %d", c)
|
t.Fatalf("expected 0 users on empty db, got %d", c)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionCRUD(t *testing.T) {
|
func TestSessionCRUD(t *testing.T) {
|
||||||
@@ -211,19 +227,27 @@ func TestForEachMap(t *testing.T) {
|
|||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
st.PutMap(tx, 1, []byte("a"))
|
if err := st.PutMap(tx, 1, []byte("a")); err != nil {
|
||||||
st.PutMap(tx, 2, []byte("b"))
|
return err
|
||||||
|
}
|
||||||
|
if err := st.PutMap(tx, 2, []byte("b")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.ForEachMap(tx, func(_, _ []byte) error {
|
return st.ForEachMap(tx, func(_, _ []byte) error {
|
||||||
count++
|
count++
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
if count != 2 {
|
if count != 2 {
|
||||||
t.Fatalf("expected 2 maps, got %d", count)
|
t.Fatalf("expected 2 maps, got %d", count)
|
||||||
}
|
}
|
||||||
@@ -290,20 +314,30 @@ func TestForEachTile(t *testing.T) {
|
|||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
st.PutTile(tx, 1, 0, "0_0", []byte("a"))
|
if err := st.PutTile(tx, 1, 0, "0_0", []byte("a")); err != nil {
|
||||||
st.PutTile(tx, 1, 1, "0_0", []byte("b"))
|
return err
|
||||||
st.PutTile(tx, 2, 0, "1_1", []byte("c"))
|
}
|
||||||
|
if err := st.PutTile(tx, 1, 1, "0_0", []byte("b")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := st.PutTile(tx, 2, 0, "1_1", []byte("c")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
return st.ForEachTile(tx, func(_, _, _, _ []byte) error {
|
return st.ForEachTile(tx, func(_, _, _, _ []byte) error {
|
||||||
count++
|
count++
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
if count != 3 {
|
if count != 3 {
|
||||||
t.Fatalf("expected 3 tiles, got %d", count)
|
t.Fatalf("expected 3 tiles, got %d", count)
|
||||||
}
|
}
|
||||||
@@ -313,7 +347,7 @@ func TestTilesMapBucket(t *testing.T) {
|
|||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
if b := st.GetTilesMapBucket(tx, 1); b != nil {
|
if b := st.GetTilesMapBucket(tx, 1); b != nil {
|
||||||
t.Fatal("expected nil bucket before creation")
|
t.Fatal("expected nil bucket before creation")
|
||||||
}
|
}
|
||||||
@@ -328,31 +362,39 @@ func TestTilesMapBucket(t *testing.T) {
|
|||||||
t.Fatal("expected non-nil after create")
|
t.Fatal("expected non-nil after create")
|
||||||
}
|
}
|
||||||
return st.DeleteTilesMapBucket(tx, 1)
|
return st.DeleteTilesMapBucket(tx, 1)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteTilesBucket(t *testing.T) {
|
func TestDeleteTilesBucket(t *testing.T) {
|
||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
st.PutTile(tx, 1, 0, "0_0", []byte("a"))
|
if err := st.PutTile(tx, 1, 0, "0_0", []byte("a")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return st.DeleteTilesBucket(tx)
|
return st.DeleteTilesBucket(tx)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
if got := st.GetTile(tx, 1, 0, "0_0"); got != nil {
|
if got := st.GetTile(tx, 1, 0, "0_0"); got != nil {
|
||||||
t.Fatal("expected nil after bucket deletion")
|
t.Fatal("expected nil after bucket deletion")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarkerBuckets(t *testing.T) {
|
func TestMarkerBuckets(t *testing.T) {
|
||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
if b := st.GetMarkersGridBucket(tx); b != nil {
|
if b := st.GetMarkersGridBucket(tx); b != nil {
|
||||||
t.Fatal("expected nil grid bucket before creation")
|
t.Fatal("expected nil grid bucket before creation")
|
||||||
}
|
}
|
||||||
@@ -376,7 +418,9 @@ func TestMarkerBuckets(t *testing.T) {
|
|||||||
t.Fatal("expected non-zero sequence")
|
t.Fatal("expected non-zero sequence")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOAuthStateCRUD(t *testing.T) {
|
func TestOAuthStateCRUD(t *testing.T) {
|
||||||
@@ -408,23 +452,29 @@ func TestBucketExistsAndDelete(t *testing.T) {
|
|||||||
st := newTestStore(t)
|
st := newTestStore(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
st.Update(ctx, func(tx *bbolt.Tx) error {
|
if err := st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||||
if st.BucketExists(tx, store.BucketUsers) {
|
if st.BucketExists(tx, store.BucketUsers) {
|
||||||
t.Fatal("expected bucket to not exist")
|
t.Fatal("expected bucket to not exist")
|
||||||
}
|
}
|
||||||
st.PutUser(tx, "alice", []byte("x"))
|
if err := st.PutUser(tx, "alice", []byte("x")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if !st.BucketExists(tx, store.BucketUsers) {
|
if !st.BucketExists(tx, store.BucketUsers) {
|
||||||
t.Fatal("expected bucket to exist")
|
t.Fatal("expected bucket to exist")
|
||||||
}
|
}
|
||||||
return st.DeleteBucket(tx, store.BucketUsers)
|
return st.DeleteBucket(tx, store.BucketUsers)
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
st.View(ctx, func(tx *bbolt.Tx) error {
|
if err := st.View(ctx, func(tx *bbolt.Tx) error {
|
||||||
if st.BucketExists(tx, store.BucketUsers) {
|
if st.BucketExists(tx, store.BucketUsers) {
|
||||||
t.Fatal("expected bucket to be deleted")
|
t.Fatal("expected bucket to be deleted")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteBucketNonExistent(t *testing.T) {
|
func TestDeleteBucketNonExistent(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user