Merge branch '179-intermittent-test-failures-on-gitlab-ci' into 'main'

Resolve "Intermittent test failures on gitlab CI"

Closes #179

See merge request devs/moth!177
This commit is contained in:
Neale Pickett 2022-05-11 02:19:57 +00:00
commit a387a06ae5
6 changed files with 39 additions and 21 deletions

View File

@ -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

View File

@ -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())

View File

@ -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.

View File

@ -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()

View File

@ -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
}

View File

@ -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
}