a test!
parent
659bf0f559
commit
39b1a6a1e8
|
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"io"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -107,7 +106,3 @@ func (db DB) dial(ctx context.Context) (*sql.DB, error) {
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db DB) GetParty(id string) (string, error) {
|
|
||||||
return "", io.EOF
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTestDB(t *testing.T) DB {
|
||||||
|
ctx, can := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer can()
|
||||||
|
conn := path.Join(t.TempDir(), "db")
|
||||||
|
|
||||||
|
db, err := NewDB(ctx, "sqlite", conn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDB(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
db := newTestDB(t)
|
||||||
|
|
||||||
|
t.Run("with lock", func(t *testing.T) {
|
||||||
|
var called [2]bool
|
||||||
|
if err := db.WithLock(func() error {
|
||||||
|
for i := range called {
|
||||||
|
if err := db.Query(ctx, func(rows *sql.Rows) error {
|
||||||
|
return rows.Scan(&called[i])
|
||||||
|
}, `SELECT true`); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !called[0] {
|
||||||
|
t.Error(0)
|
||||||
|
}
|
||||||
|
if !called[1] {
|
||||||
|
t.Error(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("exec, query", func(t *testing.T) {
|
||||||
|
if err := db.Exec(ctx, `
|
||||||
|
CREATE TABLE IF NOT EXISTS my_table (
|
||||||
|
text TEXT,
|
||||||
|
datetime DATETIME,
|
||||||
|
number NUMBER
|
||||||
|
)
|
||||||
|
`); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Exec(ctx, `
|
||||||
|
INSERT INTO my_table (
|
||||||
|
text,
|
||||||
|
datetime,
|
||||||
|
number
|
||||||
|
) VALUES (?, ?, ?)
|
||||||
|
`, "text", time.Now(), 1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var text string
|
||||||
|
var datetime time.Time
|
||||||
|
var number int
|
||||||
|
if err := db.Query(ctx, func(rows *sql.Rows) error {
|
||||||
|
return rows.Scan(&text, &datetime, &number)
|
||||||
|
}, `
|
||||||
|
SELECT
|
||||||
|
text,
|
||||||
|
datetime,
|
||||||
|
number
|
||||||
|
FROM my_table
|
||||||
|
`); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if text != "text" {
|
||||||
|
t.Error(text)
|
||||||
|
}
|
||||||
|
if datetime.IsZero() {
|
||||||
|
t.Error(datetime)
|
||||||
|
}
|
||||||
|
if number != 1 {
|
||||||
|
t.Error(number)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Games struct {
|
type Games struct {
|
||||||
|
|
@ -61,15 +63,15 @@ func (games Games) GameByName(ctx context.Context, uid, name string) (string, er
|
||||||
err := games.db.Query(ctx, func(rows *sql.Rows) error {
|
err := games.db.Query(ctx, func(rows *sql.Rows) error {
|
||||||
return rows.Scan(&result)
|
return rows.Scan(&result)
|
||||||
}, `
|
}, `
|
||||||
SELECT
|
SELECT
|
||||||
players.games_uuid
|
players.game_uuid
|
||||||
FROM
|
FROM
|
||||||
players
|
players
|
||||||
JOIN games ON players.game_uuid=games.game_uuid
|
JOIN games ON players.game_uuid=games.uuid
|
||||||
WHERE players.user_uuid=? AND games.name=?
|
WHERE players.user_uuid=? AND games.name=?
|
||||||
ORDER BY games.timestamp DESC
|
ORDER BY games.updated DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`, uid, name)
|
`, uid, name)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,6 +211,32 @@ func (games Games) GameState(ctx context.Context, id string) (GameState, error)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (games Games) CreateGame(ctx context.Context, name string) (string, error) {
|
||||||
|
var exists string
|
||||||
|
if err := games.db.Query(ctx,
|
||||||
|
func(rows *sql.Rows) error {
|
||||||
|
return rows.Scan(&exists)
|
||||||
|
},
|
||||||
|
`
|
||||||
|
SELECT uuid
|
||||||
|
FROM games
|
||||||
|
WHERE name=? AND completed IS NULL
|
||||||
|
`, name); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if exists != "" {
|
||||||
|
return exists, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.New().String()
|
||||||
|
return id, games.db.Exec(ctx, `
|
||||||
|
INSERT INTO games (
|
||||||
|
uuid,
|
||||||
|
updated,
|
||||||
|
name
|
||||||
|
) VALUES (?, ?, ?)
|
||||||
|
`, id, time.Now(), name)
|
||||||
|
}
|
||||||
|
|
||||||
func (games Games) CreateEventPlayerJoin(ctx context.Context, id string, player string) error {
|
func (games Games) CreateEventPlayerJoin(ctx context.Context, id string, player string) error {
|
||||||
return games.createEvent(ctx, id, EventPlayerJoin{ID: player})
|
return games.createEvent(ctx, id, EventPlayerJoin{ID: player})
|
||||||
}
|
}
|
||||||
|
|
@ -217,10 +245,6 @@ func (games Games) CreateEventPlayerLeave(ctx context.Context, id string, player
|
||||||
return games.createEvent(ctx, id, EventPlayerLeave{ID: player})
|
return games.createEvent(ctx, id, EventPlayerLeave{ID: player})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (games Games) CreateEventGameComplete(ctx context.Context, id string) error {
|
|
||||||
return games.createEvent(ctx, id, EventGameComplete{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string, killer, killed, killWord string) error {
|
func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string, killer, killed, killWord string) error {
|
||||||
// TODO gather current assignees
|
// TODO gather current assignees
|
||||||
// TODO get victim's target
|
// TODO get victim's target
|
||||||
|
|
@ -230,6 +254,10 @@ func (games Games) CreateEventAssignmentRotation(ctx context.Context, id string,
|
||||||
//return games.createEvent(ctx, id, v)
|
//return games.createEvent(ctx, id, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (games Games) CreateEventGameComplete(ctx context.Context, id string) error {
|
||||||
|
return games.createEvent(ctx, id, EventGameComplete{})
|
||||||
|
}
|
||||||
|
|
||||||
func (games Games) createEvent(ctx context.Context, id string, v any) error {
|
func (games Games) createEvent(ctx context.Context, id string, v any) error {
|
||||||
payload, err := json.Marshal(v)
|
payload, err := json.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTestGames(t *testing.T) Games {
|
||||||
|
db := newTestDB(t)
|
||||||
|
|
||||||
|
games, err := NewGames(context.Background(), db)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return games
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGames(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("empty", func(t *testing.T) {
|
||||||
|
games := newTestGames(t)
|
||||||
|
|
||||||
|
if v, err := games.GamesForUser(ctx, ""); err != nil {
|
||||||
|
t.Error("err getting games for empty user:", err)
|
||||||
|
} else if len(v) > 0 {
|
||||||
|
t.Error(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := games.GameByName(ctx, "", ""); err != nil {
|
||||||
|
t.Error("err getting game by empty name for empty user:", err)
|
||||||
|
} else if len(v) > 0 {
|
||||||
|
t.Error(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := games.GameState(ctx, ""); err != nil {
|
||||||
|
t.Error("err getting game state for empty:", err)
|
||||||
|
} else if len(v.Players) > 0 || !v.Completed.IsZero() {
|
||||||
|
t.Error(v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("mvp", func(t *testing.T) {
|
||||||
|
games := newTestGames(t)
|
||||||
|
|
||||||
|
id, err := games.CreateGame(ctx, "g1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("err creating game:", err)
|
||||||
|
} else if id2, err := games.CreateGame(ctx, "g1"); err != nil {
|
||||||
|
t.Fatal("err creating game redundantly:", err)
|
||||||
|
} else if id != id2 {
|
||||||
|
t.Fatal("redundant create game didnt return same id:", id2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := games.CreateEventPlayerJoin(ctx, id, "p0"); err != nil {
|
||||||
|
t.Fatal("err creating event player join:", err)
|
||||||
|
} else if err := games.CreateEventPlayerLeave(ctx, id, "p0"); err != nil {
|
||||||
|
t.Fatal("err creating event player leave:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
p := fmt.Sprintf("p%d", i+1)
|
||||||
|
if err := games.CreateEventPlayerJoin(ctx, id, p); err != nil {
|
||||||
|
t.Fatal(p, "err creating event player join", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := games.CreateEventAssignmentRotation(ctx, id, "", "", ""); err != nil {
|
||||||
|
t.Fatal("err creating rotation:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := games.GamesForUser(ctx, "p1"); err != nil {
|
||||||
|
t.Error("err getting games for user:", err)
|
||||||
|
} else if len(v) < 1 {
|
||||||
|
t.Error("no games found for user:", v)
|
||||||
|
} else if v[0] != id {
|
||||||
|
t.Error("wrong game found for user:", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := games.GameByName(ctx, "p1", "g1"); err != nil {
|
||||||
|
t.Error("err getting game by name for user:", err)
|
||||||
|
} else if v != id {
|
||||||
|
t.Error("wrong game by name for user:", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := games.GameState(ctx, id); err != nil {
|
||||||
|
t.Error("err getting game state:", err)
|
||||||
|
} else if len(v.Players) != 4 || !v.Completed.IsZero() {
|
||||||
|
t.Error("wrong game state:", v)
|
||||||
|
} else {
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
p := fmt.Sprintf("p%d", i+1)
|
||||||
|
if v.Players[p].KillWords.Global == "" {
|
||||||
|
t.Error(p, "no killwords.global")
|
||||||
|
} else if v.Players[p].KillWords.Assigned.IsZero() {
|
||||||
|
t.Error(p, "no killwords.assigned")
|
||||||
|
} else if v.Players[p].KillWords.Assignee == "" {
|
||||||
|
t.Error(p, "no killwords.assignee")
|
||||||
|
} else if len(v.Players[p].KillWords.Assignment.Public) == 0 {
|
||||||
|
t.Error(p, "no killwords.assigment.public")
|
||||||
|
} else if len(v.Players[p].KillWords.Assignment.Private) == 0 {
|
||||||
|
t.Error(p, "no killwords.assigment.private")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
|
|
@ -9,7 +9,7 @@ require (
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||||
github.com/glebarez/sqlite v1.11.0 // indirect
|
github.com/glebarez/sqlite v1.11.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -8,6 +8,8 @@ github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GM
|
||||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue