diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 65fc796..1cd0d50 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,13 +4,14 @@ stages: test: stage: test + image: golang:1.18 only: refs: - main - merge_requests script: - - go test ./... + - go test -race ./... push: stage: push diff --git a/cmd/mothd/httpd_test.go b/cmd/mothd/httpd_test.go index f5482d2..b56f56c 100644 --- a/cmd/mothd/httpd_test.go +++ b/cmd/mothd/httpd_test.go @@ -7,7 +7,6 @@ import ( "net/http/httptest" "net/url" "testing" - "time" "github.com/spf13/afero" ) @@ -34,8 +33,7 @@ func (hs *HTTPServer) TestRequest(path string, args map[string]string) *httptest func TestHttpd(t *testing.T) { server := NewTestServer() - hs := NewHTTPServer("/", server) - stateProvider := server.State.(*State) + hs := NewHTTPServer("/", server.MothServer) if r := hs.TestRequest("/", nil); r.Result().StatusCode != 200 { t.Error(r.Result()) @@ -72,7 +70,7 @@ func TestHttpd(t *testing.T) { t.Error("Register failed", r.Body.String()) } - time.Sleep(TestMaintenanceInterval) + server.refresh() if r := hs.TestRequest("/state", nil); r.Result().StatusCode != 200 { t.Error(r.Result()) @@ -114,8 +112,7 @@ func TestHttpd(t *testing.T) { t.Error("Unexpected body", r.Body.String()) } - time.Sleep(TestMaintenanceInterval) - stateProvider.refresh() + server.refresh() if r := hs.TestRequest("/content/pategory/2/puzzle.json", nil); r.Result().StatusCode != 200 { t.Error(r.Result()) @@ -127,7 +124,7 @@ func TestHttpd(t *testing.T) { } else if err := json.Unmarshal(r.Body.Bytes(), &state); err != nil { t.Error(err) } else if len(state.PointsLog) != 1 { - t.Error("Points log wrong length") + t.Errorf("Points log wrong length. Wanted 1, got %v (length %d)", state.PointsLog, len(state.PointsLog)) } else if len(state.Puzzles["pategory"]) != 2 { t.Error("Didn't unlock next puzzle") } @@ -143,7 +140,7 @@ func TestDevelMemHttpd(t *testing.T) { srv := NewTestServer() { - hs := NewHTTPServer("/", srv) + hs := NewHTTPServer("/", srv.MothServer) if r := hs.TestRequest("/mothballer/pategory.md", nil); r.Result().StatusCode != 404 { t.Error("Should have gotten a 404 for mothballer in prod mode") @@ -152,7 +149,7 @@ func TestDevelMemHttpd(t *testing.T) { { srv.Config.Devel = true - hs := NewHTTPServer("/", srv) + hs := NewHTTPServer("/", srv.MothServer) if r := hs.TestRequest("/mothballer/pategory.md", nil); r.Result().StatusCode != 500 { t.Log(r.Body.String()) diff --git a/cmd/mothd/server.go b/cmd/mothd/server.go index f53ecdf..0c5de3f 100644 --- a/cmd/mothd/server.go +++ b/cmd/mothd/server.go @@ -68,6 +68,9 @@ type Maintainer interface { // It will only be called once, when execution begins. // It's okay to just exit if there's no maintenance to be done. Maintain(updateInterval time.Duration) + + // refresh is a shortcut used internally for testing + refresh() } // MothServer gathers together the providers that make up a MOTH server. diff --git a/cmd/mothd/server_test.go b/cmd/mothd/server_test.go index ab4f986..caaf61a 100644 --- a/cmd/mothd/server_test.go +++ b/cmd/mothd/server_test.go @@ -3,30 +3,40 @@ package main import ( "io/ioutil" "testing" - "time" "github.com/spf13/afero" ) -const TestMaintenanceInterval = time.Millisecond * 1 const TestTeamID = "teamID" -func NewTestServer() *MothServer { +type TestServer struct { + *MothServer +} + +// NewTestServer creates a new MothServer with NewTestMothballs and some initial state. +// +// See function definition for details. +func NewTestServer() TestServer { puzzles := NewTestMothballs() puzzles.refresh() - go puzzles.Maintain(TestMaintenanceInterval) state := NewTestState() afero.WriteFile(state, "teamids.txt", []byte("teamID\n"), 0644) afero.WriteFile(state, "messages.html", []byte("messages.html"), 0644) state.refresh() - go state.Maintain(TestMaintenanceInterval) theme := NewTestTheme() afero.WriteFile(theme.Fs, "/index.html", []byte("index.html"), 0644) - go theme.Maintain(TestMaintenanceInterval) - return NewMothServer(Configuration{}, theme, state, puzzles) + return TestServer{NewMothServer(Configuration{}, theme, state, puzzles)} +} + +func (ts TestServer) refresh() { + ts.State.(*State).refresh() + for _, pp := range ts.PuzzleProviders { + pp.(*Mothballs).refresh() + } + ts.Theme.(*Theme).refresh() } func TestDevelServer(t *testing.T) { @@ -82,8 +92,7 @@ func TestProdServer(t *testing.T) { t.Error("index.html wrong contents", contents) } - // Wait for refresh to pick everything up - time.Sleep(TestMaintenanceInterval) + server.refresh() { es := handler.ExportState() @@ -136,7 +145,7 @@ func TestProdServer(t *testing.T) { t.Error("Right answer marked wrong", err) } - time.Sleep(TestMaintenanceInterval) + server.refresh() { es := handler.ExportState() @@ -165,7 +174,7 @@ func TestProdServer(t *testing.T) { t.Error("Right answer marked wrong:", err) } - time.Sleep(TestMaintenanceInterval) + server.refresh() { es := anonHandler.ExportState() diff --git a/cmd/mothd/theme.go b/cmd/mothd/theme.go index a70ca32..2b9b0ff 100644 --- a/cmd/mothd/theme.go +++ b/cmd/mothd/theme.go @@ -38,3 +38,7 @@ func (t *Theme) Open(name string) (ReadSeekCloser, time.Time, error) { func (t *Theme) Maintain(i time.Duration) { // No periodic tasks for a theme } + +func (t *Theme) refresh() { + // Nothing to do for a theme +} diff --git a/cmd/mothd/transpiler.go b/cmd/mothd/transpiler.go index 7103b20..ddeb3da 100644 --- a/cmd/mothd/transpiler.go +++ b/cmd/mothd/transpiler.go @@ -79,3 +79,7 @@ func (p TranspilerProvider) Mothball(cat string, w io.Writer) error { func (p TranspilerProvider) Maintain(updateInterval time.Duration) { // Nothing to do here. } + +func (p TranspilerProvider) refresh() { + // Nothing to do for a theme +}