593 lines
16 KiB
Go
593 lines
16 KiB
Go
package v01
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
func TestPatchConfig(t *testing.T) {
|
|
dir := t.TempDir()
|
|
p := path.Join(dir, t.Name()+".yaml")
|
|
cases := map[string]struct {
|
|
was config
|
|
patch string
|
|
want config
|
|
}{
|
|
"replace entire doc": {
|
|
was: config{
|
|
Feedback: configFeedback{Addr: "a", TTSURL: "a"},
|
|
Users: map[string]configUser{"a": configUser{State: configUserState{Player: 1, Message: "a"}}},
|
|
Players: []configPlayer{configPlayer{Transformation: transformation{"a": "a"}}},
|
|
Quiet: true,
|
|
},
|
|
patch: `[{"op": "replace", "path": "", "value": {
|
|
"Feedback": {"Addr": "b", "TTSURL": "b"},
|
|
"Users": {"b": {"State":{"Player": 2, "Message": "b"}}},
|
|
"Players": [{"Transformation": {"b": "b"}}],
|
|
"Quiet": false
|
|
}}]`,
|
|
want: config{
|
|
Feedback: configFeedback{Addr: "b", TTSURL: "b"},
|
|
Users: map[string]configUser{"b": configUser{State: configUserState{Player: 2, Message: "b"}}},
|
|
Players: []configPlayer{configPlayer{Transformation: transformation{"b": "b"}}},
|
|
Quiet: false,
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, d := range cases {
|
|
c := d
|
|
for _, usesdisk := range []bool{false, true} {
|
|
t.Run(fmt.Sprintf("%s disk=%v", name, usesdisk), func(t *testing.T) {
|
|
b, _ := yaml.Marshal(c.was)
|
|
os.WriteFile(p, b, os.ModePerm)
|
|
FlagParseV01Config = ""
|
|
if usesdisk {
|
|
FlagParseV01Config = p
|
|
}
|
|
v01 := &V01{cfg: c.was}
|
|
v01.cfg.lock = &sync.Mutex{}
|
|
|
|
w := httptest.NewRecorder()
|
|
r := httptest.NewRequest(http.MethodPatch, "/config", strings.NewReader(c.patch))
|
|
v01.servePatchConfig(w, r)
|
|
if fmt.Sprintf("%+v", c.want) != fmt.Sprintf("%+v", v01.cfg) {
|
|
t.Errorf("want \n\t%+v, got \n\t%+v", c.want, v01.cfg)
|
|
}
|
|
if usesdisk {
|
|
b, _ := os.ReadFile(p)
|
|
var got config
|
|
yaml.Unmarshal(b, &got)
|
|
if fmt.Sprintf("%+v", c.want) != fmt.Sprintf("%+v", v01.cfg) {
|
|
t.Errorf("want \n\t%+v, got \n\t%+v", c.want, v01.cfg)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestServeGM(t *testing.T) {
|
|
ctx, can := context.WithCancel(context.Background())
|
|
defer can()
|
|
|
|
do := func(v01 *V01, path, body string, method ...string) *httptest.ResponseRecorder {
|
|
m := http.MethodPost
|
|
if len(method) > 0 {
|
|
m = method[0]
|
|
}
|
|
w := httptest.NewRecorder()
|
|
r := httptest.NewRequest(m, path, strings.NewReader(body))
|
|
v01.ServeHTTP(w, r)
|
|
return w
|
|
}
|
|
|
|
t.Run("status", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
var result struct {
|
|
Players int `yaml:"Players"`
|
|
Users map[string]string `yaml:"Users"`
|
|
}
|
|
|
|
t.Run("empty", func(t *testing.T) {
|
|
resp := do(v01, "/gm/rpc/status", "")
|
|
if resp.Code != http.StatusOK {
|
|
t.Error(resp.Code)
|
|
}
|
|
t.Log(string(resp.Body.Bytes()))
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.Players != 0 {
|
|
t.Error(result.Players)
|
|
}
|
|
if len(result.Users) != 0 {
|
|
t.Error(result.Users)
|
|
}
|
|
})
|
|
|
|
t.Run("full", func(t *testing.T) {
|
|
v01.cfg.Players = []configPlayer{
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
}
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{
|
|
State: configUserState{Player: 3},
|
|
Meta: configUserMeta{
|
|
LastTSMS: time.Now().Add(-1*time.Minute).UnixNano() / int64(time.Millisecond),
|
|
LastLag: int64(time.Second / time.Millisecond),
|
|
},
|
|
},
|
|
"zach": configUser{},
|
|
"chase": configUser{},
|
|
"mason": configUser{},
|
|
"nat": configUser{},
|
|
"roxy": configUser{},
|
|
"bill": configUser{},
|
|
}
|
|
resp := do(v01, "/gm/rpc/status", "")
|
|
if resp.Code != http.StatusOK {
|
|
t.Error(resp.Code)
|
|
}
|
|
t.Log(string(resp.Body.Bytes()))
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.Players != 4 {
|
|
t.Error(result.Players)
|
|
}
|
|
if len(result.Users) != 7 {
|
|
t.Error(result.Users)
|
|
}
|
|
if result.Users["bel"] == "" || result.Users["bel"] == "..." {
|
|
t.Error(result.Users["bel"])
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("broadcastSomeoneSaidAlias to hotword tap", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.GM = configGM{
|
|
Hotwords: map[string]configGMHotword{
|
|
"hotword": configGMHotword{
|
|
Call: "tap",
|
|
Args: []string{"a"},
|
|
},
|
|
},
|
|
}
|
|
do(v01, "/gm/rpc/broadcastSomeoneSaidAlias?message=hotword", "")
|
|
for i := 0; i < 2; i++ {
|
|
select {
|
|
case btn := <-v01.alt:
|
|
if len(btn) != 1 {
|
|
t.Error(btn)
|
|
} else if btn[0].Down != (i == 0) {
|
|
t.Error(btn[0])
|
|
} else if btn[0].Char != 'a' {
|
|
t.Error(btn[0].Char)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("nothing in alt")
|
|
}
|
|
}
|
|
do(v01, "/gm/rpc/broadcastSomeoneSaidAlias?message=hotword", "")
|
|
time.Sleep(time.Millisecond * 150)
|
|
if got := v01.Read(); len(got) != 1 || !got[0].Down || got[0].Char != 'a' {
|
|
t.Error(got)
|
|
} else if got := v01.Read(); len(got) != 1 || got[0].Down || got[0].Char != 'a' {
|
|
t.Error(got)
|
|
}
|
|
})
|
|
|
|
t.Run("broadcastSomeoneSaidAlias", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Quiet = false
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{
|
|
GM: configUserStateGM{
|
|
Alias: "driver",
|
|
},
|
|
Message: "if someone else says 'driver', then you get to play",
|
|
}},
|
|
}
|
|
v01.cfg.Broadcast.Message = ":)"
|
|
do(v01, "/gm/rpc/broadcastSomeoneSaidAlias", "")
|
|
if !v01.cfg.Quiet {
|
|
t.Error(v01.cfg.Quiet)
|
|
}
|
|
if v := v01.cfg.Users["bel"]; v.State.GM.Alias != "" {
|
|
t.Error(v.State.GM.Alias)
|
|
} else if v.State.GM.LastAlias != "driver" {
|
|
t.Error(v.State.GM.LastAlias)
|
|
}
|
|
if bc := v01.cfg.Broadcast.Message; bc == ":)" {
|
|
t.Error(bc)
|
|
}
|
|
})
|
|
|
|
t.Run("fillNonPlayerAliases", func(t *testing.T) {
|
|
t.Run("empty", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = nil
|
|
resp := do(v01, "/gm/rpc/fillNonPlayerAliases", "[qt]")
|
|
if resp.Code != http.StatusNoContent {
|
|
t.Error(resp.Code)
|
|
}
|
|
})
|
|
|
|
t.Run("not enough", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = map[string]configUser{
|
|
"zach": configUser{State: configUserState{Player: 0}},
|
|
}
|
|
resp := do(v01, "/gm/rpc/fillNonPlayerAliases", "[]")
|
|
if resp.Code != http.StatusBadRequest {
|
|
t.Error(resp.Code)
|
|
}
|
|
})
|
|
|
|
t.Run("happy", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{Player: 1}},
|
|
"zach": configUser{State: configUserState{Player: 0}},
|
|
}
|
|
do(v01, "/gm/rpc/fillNonPlayerAliases", "[qt]")
|
|
if v := v01.cfg.Users["bel"]; v.State.GM.Alias != "" {
|
|
t.Error(v.State.GM.Alias)
|
|
} else if v.State.Player != 1 {
|
|
t.Error(v.State.Player)
|
|
}
|
|
if v := v01.cfg.Users["zach"]; v.State.GM.Alias != "qt" {
|
|
t.Error(v.State.GM.Alias)
|
|
} else if v.State.Player != 0 {
|
|
t.Error(v.State.Player)
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("vote", func(t *testing.T) {
|
|
type result map[string]string
|
|
|
|
t.Run("cast bad vote", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = map[string]configUser{"bel": {}}
|
|
resp := do(v01, "/gm/rpc/vote?user=bel&payload=?", "")
|
|
if resp.Code != http.StatusBadRequest {
|
|
t.Error(resp)
|
|
}
|
|
if v01.cfg.Users["bel"].State.Message != "" {
|
|
t.Error(v01.cfg.Users["bel"].State.Message)
|
|
}
|
|
})
|
|
|
|
t.Run("cast vote", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = map[string]configUser{"bel": {}, "zach": {}}
|
|
do(v01, "/gm/rpc/vote?user=bel&payload=zach", "")
|
|
if v01.cfg.Users["bel"].State.GM.Vote != "zach" {
|
|
t.Error(v01.cfg.Users["bel"].State.GM.Vote)
|
|
}
|
|
})
|
|
|
|
t.Run("get non vote", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = map[string]configUser{"bel": {}}
|
|
resp := do(v01, "/gm/rpc/vote", "", "GET")
|
|
var result result
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(result) != 1 {
|
|
t.Error(result)
|
|
}
|
|
if result["bel"] != "voting" {
|
|
t.Error(result)
|
|
}
|
|
t.Logf("%+v", result)
|
|
})
|
|
|
|
t.Run("get mid vote", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = map[string]configUser{"bel": {State: configUserState{GM: configUserStateGM{Vote: "zach"}, Message: "driver"}}}
|
|
resp := do(v01, "/gm/rpc/vote", "", "GET")
|
|
var result result
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(result) != 1 {
|
|
t.Error(result)
|
|
}
|
|
if result["bel"] != "voted" {
|
|
t.Error(result)
|
|
}
|
|
t.Logf("%+v", result)
|
|
})
|
|
|
|
t.Run("get empty", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = nil
|
|
resp := do(v01, "/gm/rpc/vote", "", "GET")
|
|
var result result
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(result) != 0 {
|
|
t.Error(result)
|
|
}
|
|
t.Logf("%+v", result)
|
|
})
|
|
})
|
|
|
|
t.Run("elect", func(t *testing.T) {
|
|
type result map[string]int
|
|
|
|
t.Run("happy", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{GM: configUserStateGM{Vote: "zach", LastAlias: "driver"}, Player: 1}},
|
|
"zach": configUser{State: configUserState{GM: configUserStateGM{Vote: "bel", LastAlias: "pizza"}}},
|
|
"bill": configUser{State: configUserState{GM: configUserStateGM{Vote: "bel"}, Player: 2}},
|
|
}
|
|
resp := do(v01, "/gm/rpc/elect?alias=pizza", "")
|
|
var result result
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Errorf("%s => %v", resp.Body.Bytes(), err)
|
|
}
|
|
if len(result) != 2 {
|
|
t.Error(result)
|
|
} else if result["bel"] != 2 {
|
|
t.Error(result)
|
|
} else if result["zach"] != 1 {
|
|
t.Error(result)
|
|
}
|
|
if v01.cfg.Users["bel"].State.Player != 0 {
|
|
t.Error(v01.cfg.Users["bel"].State.Player)
|
|
} else if v01.cfg.Users["zach"].State.Player != 1 {
|
|
t.Error(v01.cfg.Users["zach"].State.Player)
|
|
}
|
|
if v01.cfg.Broadcast.Message != `bel is now player 0 and zach is now player 1` {
|
|
t.Error(v01.cfg.Broadcast)
|
|
}
|
|
})
|
|
|
|
t.Run("self", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Players = []configPlayer{{}}
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{GM: configUserStateGM{Vote: "zach", LastAlias: "driver"}, Player: 1}},
|
|
"zach": configUser{State: configUserState{GM: configUserStateGM{Vote: "bel"}}},
|
|
"bill": configUser{State: configUserState{GM: configUserStateGM{Vote: "bel"}}},
|
|
}
|
|
resp := do(v01, "/gm/rpc/elect?alias=driver", "")
|
|
var result result
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(result) != 2 {
|
|
t.Error(result)
|
|
} else if result["bel"] != 2 {
|
|
t.Error(result)
|
|
} else if result["zach"] != 1 {
|
|
t.Error(result)
|
|
}
|
|
if !strings.HasSuffix(v01.cfg.Broadcast.Message, `is now player 1`) || strings.Contains(v01.cfg.Broadcast.Message, ",") {
|
|
t.Error(v01.cfg.Broadcast.Message)
|
|
}
|
|
assignments := map[int]int{}
|
|
for _, v := range v01.cfg.Users {
|
|
assignments[v.State.Player] = assignments[v.State.Player] + 1
|
|
}
|
|
if len(assignments) != 2 {
|
|
t.Error(assignments)
|
|
} else if assignments[0] != 2 {
|
|
t.Error(assignments[0])
|
|
} else if assignments[1] != 1 {
|
|
t.Error(assignments[1])
|
|
}
|
|
})
|
|
|
|
t.Run("tie", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Players = []configPlayer{{}}
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{GM: configUserStateGM{Vote: "zach", LastAlias: "driver"}, Player: 1}},
|
|
"zach": configUser{State: configUserState{GM: configUserStateGM{Vote: "bel", LastAlias: "pizza"}}},
|
|
}
|
|
resp := do(v01, "/gm/rpc/elect?alias=pizza", "")
|
|
var result result
|
|
if err := yaml.Unmarshal(resp.Body.Bytes(), &result); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(result) != 2 {
|
|
t.Error(result)
|
|
} else if result["bel"] != 1 {
|
|
t.Error(result)
|
|
} else if result["zach"] != 1 {
|
|
t.Error(result)
|
|
}
|
|
if bc := v01.cfg.Broadcast.Message; !strings.HasSuffix(bc, `is now player 1`) || strings.Contains(bc, ",") {
|
|
t.Error(bc)
|
|
}
|
|
assignments := map[int]int{}
|
|
for _, v := range v01.cfg.Users {
|
|
assignments[v.State.Player] = assignments[v.State.Player] + 1
|
|
}
|
|
if len(assignments) != 2 {
|
|
t.Error(assignments)
|
|
} else if assignments[0] != 1 {
|
|
t.Error(assignments[0])
|
|
} else if assignments[1] != 1 {
|
|
t.Error(assignments[1])
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("shuffle", func(t *testing.T) {
|
|
t.Run("many 2u 2p", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
for i := 0; i < 100; i++ {
|
|
v01.cfg.Quiet = true
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{Player: 1}},
|
|
"zach": configUser{State: configUserState{Player: 2}},
|
|
}
|
|
v01.cfg.Players = []configPlayer{{}, {}}
|
|
do(v01, "/gm/rpc/shuffle", "")
|
|
if v01.cfg.Quiet {
|
|
t.Error(v01.cfg.Quiet)
|
|
}
|
|
if len(v01.cfg.Users) != 2 {
|
|
t.Error(v01.cfg.Users)
|
|
} else if len(v01.cfg.Players) != 2 {
|
|
t.Error(v01.cfg.Users)
|
|
} else if bp := v01.cfg.Users["bel"].State.Player; bp != 1 && bp != 2 {
|
|
t.Error(bp)
|
|
} else if zp := v01.cfg.Users["zach"].State.Player; zp != 1 && zp != 2 {
|
|
t.Error(zp)
|
|
} else if bp == zp {
|
|
t.Error(bp, zp)
|
|
}
|
|
}
|
|
})
|
|
|
|
cases := map[string]struct {
|
|
users int
|
|
usersAssigned int
|
|
players int
|
|
}{
|
|
"empty": {},
|
|
"just users": {users: 2},
|
|
"just players": {players: 2},
|
|
"2 unassigned users and 2 players": {users: 2, players: 2},
|
|
"2 users and 2 players": {users: 2, usersAssigned: 2, players: 2},
|
|
"1 users and 2 players": {users: 1, usersAssigned: 1, players: 2},
|
|
"1 unassigned users and 2 players": {users: 1, players: 2},
|
|
"4 players for 7 users 0 assigned": {users: 7, players: 4},
|
|
"4 players for 7 users 4 assigned": {users: 7, players: 4, usersAssigned: 4},
|
|
}
|
|
|
|
for name, d := range cases {
|
|
c := d
|
|
t.Run(name, func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Quiet = true
|
|
v01.cfg.Users = map[string]configUser{}
|
|
for i := 0; i < c.users; i++ {
|
|
v01.cfg.Users[strconv.Itoa(i)] = configUser{}
|
|
if i < c.usersAssigned {
|
|
v01.cfg.Users[strconv.Itoa(i)] = configUser{State: configUserState{Player: i}}
|
|
}
|
|
}
|
|
v01.cfg.Players = make([]configPlayer, c.players)
|
|
|
|
do(v01, "/gm/rpc/shuffle", "")
|
|
if v01.cfg.Quiet {
|
|
t.Error(v01.cfg.Quiet)
|
|
}
|
|
|
|
if len(v01.cfg.Users) != c.users {
|
|
t.Error(v01.cfg.Users)
|
|
} else if len(v01.cfg.Players) != c.players {
|
|
t.Error(v01.cfg.Users)
|
|
}
|
|
for i := 0; i < c.users; i++ {
|
|
if _, ok := v01.cfg.Users[strconv.Itoa(i)]; !ok {
|
|
t.Error(i)
|
|
}
|
|
}
|
|
assignments := map[int]int{}
|
|
for _, v := range v01.cfg.Users {
|
|
if v.State.Player > 0 {
|
|
assignments[v.State.Player] = assignments[v.State.Player] + 1
|
|
}
|
|
}
|
|
lesser := c.users
|
|
if c.players < lesser {
|
|
lesser = c.players
|
|
}
|
|
if len(assignments) != lesser {
|
|
t.Error(assignments)
|
|
}
|
|
for _, v := range assignments {
|
|
if v != 1 {
|
|
t.Error(v)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("swap", func(t *testing.T) {
|
|
t.Run("self", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Quiet = true
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{Player: 1}},
|
|
}
|
|
resp := do(v01, "/gm/rpc/swap?a=bel&b=bel", "")
|
|
if resp.Code != http.StatusConflict {
|
|
t.Error(resp.Code)
|
|
}
|
|
if !v01.cfg.Quiet {
|
|
t.Error(v01.cfg.Quiet)
|
|
}
|
|
})
|
|
|
|
t.Run("who", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Quiet = true
|
|
resp := do(v01, "/gm/rpc/swap?a=bel", "")
|
|
if resp.Code != http.StatusBadRequest {
|
|
t.Error(resp.Code)
|
|
}
|
|
if !v01.cfg.Quiet {
|
|
t.Error(v01.cfg.Quiet)
|
|
}
|
|
})
|
|
|
|
t.Run("happy", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
v01.cfg.Quiet = true
|
|
v01.cfg.Users = map[string]configUser{
|
|
"bel": configUser{State: configUserState{Player: 1}},
|
|
"zach": configUser{State: configUserState{Player: 2}},
|
|
}
|
|
resp := do(v01, "/gm/rpc/swap?a=bel&b=zach", "")
|
|
if resp.Code != http.StatusOK {
|
|
t.Error(resp.Code)
|
|
}
|
|
if v01.cfg.Quiet {
|
|
t.Error(v01.cfg.Quiet)
|
|
}
|
|
if v01.cfg.Users["bel"].State.Player != 2 {
|
|
t.Error(v01.cfg.Users["bel"])
|
|
} else if v01.cfg.Users["zach"].State.Player != 1 {
|
|
t.Error(v01.cfg.Users["zach"])
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("404", func(t *testing.T) {
|
|
v01 := NewV01(ctx, nil)
|
|
resp := do(v01, "/gm/teehee", "")
|
|
if resp.Code != http.StatusNotFound {
|
|
t.Error(resp.Code)
|
|
}
|
|
})
|
|
}
|