From f49d1c3801f79757ad521adb18a1e0a15af5a226 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Wed, 19 Aug 2020 18:01:21 -0600 Subject: [PATCH] Server tests --- cmd/mothd/httpd.go | 4 +- cmd/mothd/httpd_test.go | 10 +++++ cmd/mothd/main.go | 4 +- cmd/mothd/main_test.go | 12 ------ cmd/mothd/mothballs_test.go | 27 +++++++++--- cmd/mothd/server.go | 15 +++++-- cmd/mothd/server_test.go | 86 +++++++++++++++++++++++++++++++++++++ cmd/mothd/state.go | 10 ++--- cmd/mothd/state_test.go | 2 +- 9 files changed, 137 insertions(+), 33 deletions(-) create mode 100644 cmd/mothd/httpd_test.go delete mode 100644 cmd/mothd/main_test.go create mode 100644 cmd/mothd/server_test.go diff --git a/cmd/mothd/httpd.go b/cmd/mothd/httpd.go index 7342260..7540cd7 100644 --- a/cmd/mothd/httpd.go +++ b/cmd/mothd/httpd.go @@ -38,7 +38,9 @@ func (h *HTTPServer) HandleMothFunc( mothHandler func(MothRequestHandler, http.ResponseWriter, *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) } h.HandleFunc(h.base+pattern, handler) diff --git a/cmd/mothd/httpd_test.go b/cmd/mothd/httpd_test.go new file mode 100644 index 0000000..fe08ad4 --- /dev/null +++ b/cmd/mothd/httpd_test.go @@ -0,0 +1,10 @@ +package main + +import ( + "testing" +) + +func TestHttpd(t *testing.T) { + //emptyBody := bytes.NewReader([]byte{}) + //request := httptest.NewRequest("GET", "/", emptyBody) +} diff --git a/cmd/mothd/main.go b/cmd/mothd/main.go index b77a258..5aa59ee 100644 --- a/cmd/mothd/main.go +++ b/cmd/mothd/main.go @@ -2,7 +2,6 @@ package main import ( "flag" - "log" "mime" "time" @@ -10,8 +9,6 @@ import ( ) func main() { - log.Print("Started") - themePath := flag.String( "theme", "theme", @@ -59,5 +56,6 @@ func main() { server := NewMothServer(puzzles, theme, state) httpd := NewHTTPServer(*base, server) + httpd.Run(*bindStr) } diff --git a/cmd/mothd/main_test.go b/cmd/mothd/main_test.go deleted file mode 100644 index 5735e86..0000000 --- a/cmd/mothd/main_test.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "testing" -) - -func TestEverything(t *testing.T) { - state := NewTestState() - t.Error("No test") - - state.refresh() -} diff --git a/cmd/mothd/mothballs_test.go b/cmd/mothd/mothballs_test.go index ac94e1c..d27dd83 100644 --- a/cmd/mothd/mothballs_test.go +++ b/cmd/mothd/mothballs_test.go @@ -12,8 +12,9 @@ var testFiles = []struct { Name, Body string }{ {"puzzles.txt", "1"}, + {"answers.txt", "1 answer123\n1 answer456\n"}, {"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) { @@ -29,11 +30,16 @@ func (m *Mothballs) createMothball(cat string) { } } -func TestMothballs(t *testing.T) { +func NewTestMothballs() *Mothballs { m := NewMothballs(new(afero.MemMapFs)) - m.createMothball("test1") + m.createMothball("pategory") 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") } @@ -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.Fs.Remove("test1.mb") + m.Fs.Remove("pategory.mb") m.refresh() inv = m.Inventory() if len(inv) != 1 { t.Error("Deleted mothball is still around", inv) } + } diff --git a/cmd/mothd/server.go b/cmd/mothd/server.go index e363f3e..395445b 100644 --- a/cmd/mothd/server.go +++ b/cmd/mothd/server.go @@ -54,6 +54,7 @@ type StateProvider interface { TeamName(teamID string) (string, error) SetTeamName(teamID, teamName string) error AwardPoints(teamID string, cat string, points int) error + LogEvent(msg string) Maintainer } @@ -82,17 +83,19 @@ func NewMothServer(puzzles PuzzleProvider, theme ThemeProvider, state StateProvi } // 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{ - MothServer: s, - teamID: teamID, + MothServer: s, + participantID: participantID, + teamID: teamID, } } // MothRequestHandler provides http.RequestHandler for a MothServer. type MothRequestHandler struct { *MothServer - teamID string + participantID string + teamID string } // PuzzlesOpen opens a file associated with a puzzle. @@ -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 func (mh *MothRequestHandler) CheckAnswer(cat string, points int, answer string) error { 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 } 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 } diff --git a/cmd/mothd/server_test.go b/cmd/mothd/server_test.go new file mode 100644 index 0000000..4d21e80 --- /dev/null +++ b/cmd/mothd/server_test.go @@ -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!") + } +} diff --git a/cmd/mothd/state.go b/cmd/mothd/state.go index 7bb955d..dd7f48f 100644 --- a/cmd/mothd/state.go +++ b/cmd/mothd/state.go @@ -204,7 +204,9 @@ func (s *State) AwardPoints(teamID, category string, points int) error { return err } - // BUG(neale): When points are awarded, state should be updated immediately + // State should be updated immediately + s.refreshNow <- true + return nil } @@ -342,12 +344,6 @@ func (s *State) LogEvent(msg string) { 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 { if s.eventWriter != nil { if err := s.eventWriter.Close(); err != nil { diff --git a/cmd/mothd/state_test.go b/cmd/mothd/state_test.go index def59a4..0785c51 100644 --- a/cmd/mothd/state_test.go +++ b/cmd/mothd/state_test.go @@ -78,7 +78,7 @@ func TestState(t *testing.T) { func TestStateEvents(t *testing.T) { s := NewTestState() s.LogEvent("moo") - s.LogEventf("moo %d", 2) + s.LogEvent("moo 2") if msg := <-s.eventStream; msg != "moo" { t.Error("Wrong message from event stream", msg)