Server tests

This commit is contained in:
Neale Pickett 2020-08-19 18:01:21 -06:00
parent f8556dd2e5
commit f49d1c3801
9 changed files with 137 additions and 33 deletions

View File

@ -38,7 +38,9 @@ func (h *HTTPServer) HandleMothFunc(
mothHandler func(MothRequestHandler, http.ResponseWriter, *http.Request), mothHandler func(MothRequestHandler, http.ResponseWriter, *http.Request),
) { ) {
handler := func(w http.ResponseWriter, req *http.Request) { handler := func(w http.ResponseWriter, req *http.Request) {
mh := h.server.NewHandler(req.FormValue("id")) participantID := req.FormValue("pid")
teamID := req.FormValue("id")
mh := h.server.NewHandler(participantID, teamID)
mothHandler(mh, w, req) mothHandler(mh, w, req)
} }
h.HandleFunc(h.base+pattern, handler) h.HandleFunc(h.base+pattern, handler)

10
cmd/mothd/httpd_test.go Normal file
View File

@ -0,0 +1,10 @@
package main
import (
"testing"
)
func TestHttpd(t *testing.T) {
//emptyBody := bytes.NewReader([]byte{})
//request := httptest.NewRequest("GET", "/", emptyBody)
}

View File

@ -2,7 +2,6 @@ package main
import ( import (
"flag" "flag"
"log"
"mime" "mime"
"time" "time"
@ -10,8 +9,6 @@ import (
) )
func main() { func main() {
log.Print("Started")
themePath := flag.String( themePath := flag.String(
"theme", "theme",
"theme", "theme",
@ -59,5 +56,6 @@ func main() {
server := NewMothServer(puzzles, theme, state) server := NewMothServer(puzzles, theme, state)
httpd := NewHTTPServer(*base, server) httpd := NewHTTPServer(*base, server)
httpd.Run(*bindStr) httpd.Run(*bindStr)
} }

View File

@ -1,12 +0,0 @@
package main
import (
"testing"
)
func TestEverything(t *testing.T) {
state := NewTestState()
t.Error("No test")
state.refresh()
}

View File

@ -12,8 +12,9 @@ var testFiles = []struct {
Name, Body string Name, Body string
}{ }{
{"puzzles.txt", "1"}, {"puzzles.txt", "1"},
{"answers.txt", "1 answer123\n1 answer456\n"},
{"content/1/puzzle.json", `{"name": "moo"}`}, {"content/1/puzzle.json", `{"name": "moo"}`},
{"content/1/moo.txt", `My cow goes "moo"`}, {"content/1/moo.txt", `moo`},
} }
func (m *Mothballs) createMothball(cat string) { func (m *Mothballs) createMothball(cat string) {
@ -29,11 +30,16 @@ func (m *Mothballs) createMothball(cat string) {
} }
} }
func TestMothballs(t *testing.T) { func NewTestMothballs() *Mothballs {
m := NewMothballs(new(afero.MemMapFs)) m := NewMothballs(new(afero.MemMapFs))
m.createMothball("test1") m.createMothball("pategory")
m.refresh() m.refresh()
if _, ok := m.categories["test1"]; !ok { return m
}
func TestMothballs(t *testing.T) {
m := NewTestMothballs()
if _, ok := m.categories["pategory"]; !ok {
t.Error("Didn't create a new category") t.Error("Didn't create a new category")
} }
@ -52,11 +58,22 @@ func TestMothballs(t *testing.T) {
} }
} }
if err := m.CheckAnswer("pategory", 1, "answer"); err == nil {
t.Error("Wrong answer marked right")
}
if err := m.CheckAnswer("pategory", 1, "answer123"); err != nil {
t.Error("Right answer marked wrong", err)
}
if err := m.CheckAnswer("pategory", 1, "answer456"); err != nil {
t.Error("Right answer marked wrong", err)
}
m.createMothball("test2") m.createMothball("test2")
m.Fs.Remove("test1.mb") m.Fs.Remove("pategory.mb")
m.refresh() m.refresh()
inv = m.Inventory() inv = m.Inventory()
if len(inv) != 1 { if len(inv) != 1 {
t.Error("Deleted mothball is still around", inv) t.Error("Deleted mothball is still around", inv)
} }
} }

View File

@ -54,6 +54,7 @@ type StateProvider interface {
TeamName(teamID string) (string, error) TeamName(teamID string) (string, error)
SetTeamName(teamID, teamName string) error SetTeamName(teamID, teamName string) error
AwardPoints(teamID string, cat string, points int) error AwardPoints(teamID string, cat string, points int) error
LogEvent(msg string)
Maintainer Maintainer
} }
@ -82,9 +83,10 @@ func NewMothServer(puzzles PuzzleProvider, theme ThemeProvider, state StateProvi
} }
// NewHandler returns a new http.RequestHandler for the provided teamID. // NewHandler returns a new http.RequestHandler for the provided teamID.
func (s *MothServer) NewHandler(teamID string) MothRequestHandler { func (s *MothServer) NewHandler(participantID, teamID string) MothRequestHandler {
return MothRequestHandler{ return MothRequestHandler{
MothServer: s, MothServer: s,
participantID: participantID,
teamID: teamID, teamID: teamID,
} }
} }
@ -92,6 +94,7 @@ func (s *MothServer) NewHandler(teamID string) MothRequestHandler {
// MothRequestHandler provides http.RequestHandler for a MothServer. // MothRequestHandler provides http.RequestHandler for a MothServer.
type MothRequestHandler struct { type MothRequestHandler struct {
*MothServer *MothServer
participantID string
teamID string teamID string
} }
@ -126,10 +129,14 @@ func (mh *MothRequestHandler) Register(teamName string) error {
// CheckAnswer returns an error if answer is not a correct answer for puzzle points in category cat // CheckAnswer returns an error if answer is not a correct answer for puzzle points in category cat
func (mh *MothRequestHandler) CheckAnswer(cat string, points int, answer string) error { func (mh *MothRequestHandler) CheckAnswer(cat string, points int, answer string) error {
if err := mh.Puzzles.CheckAnswer(cat, points, answer); err != nil { if err := mh.Puzzles.CheckAnswer(cat, points, answer); err != nil {
msg := fmt.Sprintf("BAD %s %s %s %d %s", mh.participantID, mh.teamID, cat, points, err.Error())
mh.State.LogEvent(msg)
return err return err
} }
if err := mh.State.AwardPoints(mh.teamID, cat, points); err != nil { if err := mh.State.AwardPoints(mh.teamID, cat, points); err != nil {
msg := fmt.Sprintf("GOOD %s %s %s %d", mh.participantID, mh.teamID, cat, points)
mh.State.LogEvent(msg)
return err return err
} }

86
cmd/mothd/server_test.go Normal file
View File

@ -0,0 +1,86 @@
package main
import (
"io/ioutil"
"testing"
"time"
"github.com/spf13/afero"
)
const TestMaintenanceInterval = time.Millisecond * 1
const TestTeamID = "teamID"
func NewTestServer() *MothServer {
puzzles := NewTestMothballs()
go puzzles.Maintain(TestMaintenanceInterval)
state := NewTestState()
afero.WriteFile(state, "teamids.txt", []byte("teamID\n"), 0644)
afero.WriteFile(state, "messages.html", []byte("messages.html"), 0644)
go state.Maintain(TestMaintenanceInterval)
theme := NewTestTheme()
afero.WriteFile(theme.Fs, "index.html", []byte("index.html"), 0644)
go theme.Maintain(TestMaintenanceInterval)
return NewMothServer(puzzles, theme, state)
}
func TestServer(t *testing.T) {
teamName := "OurTeam"
participantID := "participantID"
teamID := TestTeamID
server := NewTestServer()
handler := server.NewHandler(participantID, teamID)
if err := handler.Register(teamName); err != nil {
t.Error(err)
}
if r, _, err := handler.ThemeOpen("index.html"); err != nil {
t.Error(err)
} else if contents, err := ioutil.ReadAll(r); err != nil {
t.Error(err)
} else if string(contents) != "index.html" {
t.Error("index.html wrong contents", contents)
}
es := handler.ExportState()
if es.Config.Devel {
t.Error("Marked as development server")
}
if len(es.Puzzles) != 1 {
t.Error("Puzzle categories wrong length")
}
if es.Messages != "messages.html" {
t.Error("Messages has wrong contents")
}
if len(es.PointsLog) != 0 {
t.Error("Points log not empty")
}
if len(es.TeamNames) != 1 {
t.Error("Wrong number of team names")
}
if es.TeamNames["self"] != teamName {
t.Error("TeamNames['self'] wrong")
}
if r, _, err := handler.PuzzlesOpen("pategory", 1, "moo.txt"); err != nil {
t.Error(err)
} else if contents, err := ioutil.ReadAll(r); err != nil {
t.Error(err)
} else if string(contents) != "moo" {
t.Error("moo.txt has wrong contents", contents)
}
if err := handler.CheckAnswer("pategory", 1, "answer123"); err != nil {
t.Error("Right answer marked wrong", err)
}
time.Sleep(TestMaintenanceInterval)
es = handler.ExportState()
if len(es.PointsLog) != 1 {
t.Error("I didn't get my points!")
}
}

View File

@ -204,7 +204,9 @@ func (s *State) AwardPoints(teamID, category string, points int) error {
return err return err
} }
// BUG(neale): When points are awarded, state should be updated immediately // State should be updated immediately
s.refreshNow <- true
return nil return nil
} }
@ -342,12 +344,6 @@ func (s *State) LogEvent(msg string) {
s.eventStream <- msg s.eventStream <- msg
} }
// LogEventf writes a formatted message to the event log
func (s *State) LogEventf(format string, a ...interface{}) {
msg := fmt.Sprintf(format, a...)
s.LogEvent(msg)
}
func (s *State) reopenEventLog() error { func (s *State) reopenEventLog() error {
if s.eventWriter != nil { if s.eventWriter != nil {
if err := s.eventWriter.Close(); err != nil { if err := s.eventWriter.Close(); err != nil {

View File

@ -78,7 +78,7 @@ func TestState(t *testing.T) {
func TestStateEvents(t *testing.T) { func TestStateEvents(t *testing.T) {
s := NewTestState() s := NewTestState()
s.LogEvent("moo") s.LogEvent("moo")
s.LogEventf("moo %d", 2) s.LogEvent("moo 2")
if msg := <-s.eventStream; msg != "moo" { if msg := <-s.eventStream; msg != "moo" {
t.Error("Wrong message from event stream", msg) t.Error("Wrong message from event stream", msg)