Neale Pickett
·
2023-09-29
server_test.go
1package main
2
3import (
4 "io/ioutil"
5 "testing"
6
7 "github.com/spf13/afero"
8)
9
10const TestTeamID = "teamID"
11
12type TestServer struct {
13 *MothServer
14}
15
16// NewTestServer creates a new MothServer with NewTestMothballs and some initial state.
17//
18// See function definition for details.
19func NewTestServer() TestServer {
20 puzzles := NewTestMothballs()
21 puzzles.refresh()
22
23 state := NewTestState()
24 afero.WriteFile(state, "teamids.txt", []byte("teamID\n"), 0644)
25 state.refresh()
26
27 theme := NewTestTheme()
28 afero.WriteFile(theme.Fs, "/index.html", []byte("index.html"), 0644)
29
30 return TestServer{NewMothServer(Configuration{}, theme, state, puzzles)}
31}
32
33func (ts TestServer) refresh() {
34 ts.State.(*State).refresh()
35 for _, pp := range ts.PuzzleProviders {
36 pp.(*Mothballs).refresh()
37 }
38 ts.Theme.(*Theme).refresh()
39}
40
41func TestDevelServer(t *testing.T) {
42 server := NewTestServer()
43 server.Config.Devel = true
44 anonHandler := server.NewHandler("badTeamId")
45
46 {
47 es := anonHandler.ExportState()
48 if !es.Config.Devel {
49 t.Error("Not marked as development server")
50 }
51 if len(es.Puzzles) != 1 {
52 t.Error("Wrong puzzles for anonymous state on devel server:", es.Puzzles)
53 }
54 }
55}
56
57func TestProdServer(t *testing.T) {
58 teamName := "OurTeam"
59 teamID := TestTeamID
60
61 server := NewTestServer()
62 handler := server.NewHandler(teamID)
63 anonHandler := server.NewHandler("badTeamId")
64
65 {
66 es := handler.ExportState()
67 if es.Config.Devel {
68 t.Error("Marked as development server", es.Config)
69 }
70 if len(es.Puzzles) != 0 {
71 t.Log("State", es)
72 t.Error("Unauthenticated state has non-empty puzzles list")
73 }
74 }
75
76 if err := handler.Register(teamName); err != nil {
77 t.Error(err)
78 }
79 if err := handler.Register(teamName); err == nil {
80 t.Error("Registering twice should have raised an error")
81 } else if err != ErrAlreadyRegistered {
82 t.Error("Wrong error for duplicate registration:", err)
83 }
84
85 if r, _, err := handler.ThemeOpen("/index.html"); err != nil {
86 t.Error(err)
87 } else if contents, err := ioutil.ReadAll(r); err != nil {
88 t.Error(err)
89 } else if string(contents) != "index.html" {
90 t.Error("index.html wrong contents", contents)
91 }
92
93 server.refresh()
94
95 {
96 es := handler.ExportState()
97 if es.Config.Devel {
98 t.Error("Marked as development server", es.Config)
99 }
100 if len(es.Puzzles) != 1 {
101 t.Error("Puzzle categories wrong length", len(es.Puzzles))
102 }
103 if len(es.PointsLog) != 0 {
104 t.Error("Points log not empty")
105 }
106 if len(es.TeamNames) != 1 {
107 t.Error("Wrong number of team names")
108 }
109 if es.TeamNames["self"] != teamName {
110 t.Error("TeamNames['self'] wrong")
111 }
112 }
113
114 if r, _, err := handler.PuzzlesOpen("pategory", 1, "moo.txt"); err != nil {
115 t.Error(err)
116 } else if contents, err := ioutil.ReadAll(r); err != nil {
117 r.Close()
118 t.Error(err)
119 } else if string(contents) != "moo" {
120 r.Close()
121 t.Error("moo.txt has wrong contents", contents)
122 } else {
123 r.Close()
124 }
125
126 if r, _, err := handler.PuzzlesOpen("pategory", 2, "puzzle.json"); err == nil {
127 t.Error("Opening locked puzzle shouldn't work")
128 r.Close()
129 }
130
131 if r, _, err := handler.PuzzlesOpen("pategory", 20, "puzzle.json"); err == nil {
132 t.Error("Opening non-existent puzzle shouldn't work")
133 r.Close()
134 }
135
136 if err := anonHandler.CheckAnswer("pategory", 1, "answer123"); err == nil {
137 t.Error("Invalid team ID was able to get points with correct answer")
138 }
139 if err := handler.CheckAnswer("pategory", 1, "answer123"); err != nil {
140 t.Error("Right answer marked wrong", err)
141 }
142
143 server.refresh()
144
145 {
146 es := handler.ExportState()
147 if len(es.PointsLog) != 1 {
148 t.Error("I didn't get my points!")
149 }
150 if len(es.Puzzles["pategory"]) != 2 {
151 t.Error("The next puzzle didn't unlock!")
152 } else if es.Puzzles["pategory"][1] != 2 {
153 t.Error("The 2-point puzzle should have unlocked!")
154 }
155 }
156
157 if r, _, err := handler.PuzzlesOpen("pategory", 2, "puzzle.json"); err != nil {
158 t.Error("Opening unlocked puzzle should work")
159 } else {
160 r.Close()
161 }
162 if r, _, err := anonHandler.PuzzlesOpen("pategory", 2, "puzzle.json"); err != nil {
163 t.Error("Opening unlocked puzzle anonymously should work")
164 } else {
165 r.Close()
166 }
167
168 if err := handler.CheckAnswer("pategory", 2, "wat"); err != nil {
169 t.Error("Right answer marked wrong:", err)
170 }
171
172 server.refresh()
173
174 {
175 es := anonHandler.ExportState()
176 if len(es.TeamNames) != 1 {
177 t.Error("Anonymous TeamNames is wrong:", es.TeamNames)
178 }
179 if len(es.PointsLog) != 2 {
180 t.Errorf("Points log wrong length: got %d, wanted 2", len(es.PointsLog))
181 } else if es.PointsLog[1].TeamID != "0" {
182 t.Error("Second point log didn't anonymize team ID correctly:", es.PointsLog[1])
183 }
184 }
185
186 {
187 es := handler.ExportState()
188 if len(es.TeamNames) != 1 {
189 t.Error("TeamNames is wrong:", es.TeamNames)
190 }
191 }
192
193 // BUG(neale): We aren't currently testing the various ways to disable the server
194}