2020-08-19 18:01:21 -06:00
package main
import (
2020-08-21 17:02:38 -06:00
"bytes"
"encoding/json"
"fmt"
2021-10-20 11:29:55 -06:00
"io/ioutil"
"log"
2020-08-21 17:02:38 -06:00
"net/http/httptest"
"net/url"
2021-10-20 11:29:55 -06:00
"strings"
2020-08-19 18:01:21 -06:00
"testing"
2020-09-15 15:58:21 -06:00
"github.com/spf13/afero"
2020-08-19 18:01:21 -06:00
)
2020-08-21 17:02:38 -06:00
const TestParticipantID = "shipox"
func ( hs * HTTPServer ) TestRequest ( path string , args map [ string ] string ) * httptest . ResponseRecorder {
vals := url . Values { }
vals . Set ( "pid" , TestParticipantID )
vals . Set ( "id" , TestTeamID )
2021-10-13 18:25:27 -06:00
for k , v := range args {
vals . Set ( k , v )
2020-08-21 17:02:38 -06:00
}
recorder := httptest . NewRecorder ( )
request := httptest . NewRequest (
"GET" ,
fmt . Sprintf ( "%s?%s" , path , vals . Encode ( ) ) ,
bytes . NewReader ( [ ] byte { } ) ,
)
hs . ServeHTTP ( recorder , request )
return recorder
}
2020-08-19 18:01:21 -06:00
func TestHttpd ( t * testing . T ) {
2021-10-20 11:29:55 -06:00
server := NewTestServer ( )
2022-05-10 19:48:51 -06:00
hs := NewHTTPServer ( "/" , server . MothServer )
2020-08-21 17:02:38 -06:00
if r := hs . TestRequest ( "/" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
}
if r := hs . TestRequest ( "/index.html" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
}
if r := hs . TestRequest ( "/rolodex.html" , nil ) ; r . Result ( ) . StatusCode != 404 {
t . Error ( r . Result ( ) )
}
if r := hs . TestRequest ( "/state" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
2020-10-14 10:05:53 -06:00
} else if r . Body . String ( ) != ` { "Config": { "Devel":false},"Messages":"messages.html","TeamNames": { },"PointsLog":[],"Puzzles": { }} ` {
2020-10-13 16:41:50 -06:00
t . Error ( "Unexpected state" , r . Body . String ( ) )
2020-08-21 17:02:38 -06:00
}
if r := hs . TestRequest ( "/register" , map [ string ] string { "id" : "bad team id" , "name" : "GoTeam" } ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
2021-10-13 18:25:27 -06:00
} else if r . Body . String ( ) != ` { "status":"fail","data": { "short":"not registered","description":"team ID not found in list of valid team IDs"}} ` {
2020-08-21 17:02:38 -06:00
t . Error ( "Register bad team ID failed" )
}
if r := hs . TestRequest ( "/register" , map [ string ] string { "name" : "GoTeam" } ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
2021-10-13 18:25:27 -06:00
} else if r . Body . String ( ) != ` { "status":"success","data": { "short":"registered","description":"team ID registered"}} ` {
2020-08-21 17:02:38 -06:00
t . Error ( "Register failed" )
}
2020-10-13 19:48:37 -06:00
if r := hs . TestRequest ( "/register" , map [ string ] string { "name" : "GoTeam" } ) ; r . Result ( ) . StatusCode != 200 {
2020-10-13 18:33:12 -06:00
t . Error ( r . Result ( ) )
2021-10-13 18:25:27 -06:00
} else if r . Body . String ( ) != ` { "status":"success","data": { "short":"already registered","description":"team ID has already been registered"}} ` {
2020-10-13 18:33:12 -06:00
t . Error ( "Register failed" , r . Body . String ( ) )
}
2022-05-10 19:48:51 -06:00
server . refresh ( )
2021-10-26 12:48:23 -06:00
2020-08-21 17:02:38 -06:00
if r := hs . TestRequest ( "/state" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
} else if r . Body . String ( ) != ` { "Config": { "Devel":false},"Messages":"messages.html","TeamNames": { "self":"GoTeam"},"PointsLog":[],"Puzzles": { "pategory":[1]}} ` {
t . Error ( "Unexpected state" , r . Body . String ( ) )
}
if r := hs . TestRequest ( "/content/pategory" , nil ) ; r . Result ( ) . StatusCode != 404 {
t . Error ( r . Result ( ) )
}
if r := hs . TestRequest ( "/content/pategory/1/not-here" , nil ) ; r . Result ( ) . StatusCode != 404 {
t . Error ( r . Result ( ) )
}
if r := hs . TestRequest ( "/content/pategory/2/moo.txt" , nil ) ; r . Result ( ) . StatusCode != 404 {
t . Error ( r . Result ( ) )
}
if r := hs . TestRequest ( "/content/pategory/1/" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
}
if r := hs . TestRequest ( "/content/pategory/1/moo.txt" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
} else if r . Body . String ( ) != ` moo ` {
t . Error ( "Unexpected body" , r . Body . String ( ) )
}
if r := hs . TestRequest ( "/answer" , map [ string ] string { "cat" : "pategory" , "points" : "1" , "answer" : "moo" } ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
2021-10-13 18:25:27 -06:00
} else if r . Body . String ( ) != ` { "status":"fail","data": { "short":"not accepted","description":"incorrect answer"}} ` {
2020-08-21 17:02:38 -06:00
t . Error ( "Unexpected body" , r . Body . String ( ) )
}
if r := hs . TestRequest ( "/answer" , map [ string ] string { "cat" : "pategory" , "points" : "1" , "answer" : "answer123" } ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
2021-10-20 11:29:55 -06:00
} else if strings . Contains ( r . Body . String ( ) , "incorrect answer" ) {
// Pernicious intermittent bug
t . Error ( "Incorrect answer that was actually correct" )
for _ , provider := range server . PuzzleProviders {
if mb , ok := provider . ( * Mothballs ) ; ! ok {
t . Error ( "Provider is not a mothball" )
} else {
cat , _ := mb . getCat ( "pategory" )
f , _ := cat . Open ( "answers.txt" )
defer f . Close ( )
answersBytes , _ := ioutil . ReadAll ( f )
t . Errorf ( "Correct answers: %v" , string ( answersBytes ) )
}
}
t . Error ( "Wrong answer" )
2020-08-21 17:02:38 -06:00
} else if r . Body . String ( ) != ` { "status":"success","data": { "short":"accepted","description":"1 points awarded in pategory"}} ` {
t . Error ( "Unexpected body" , r . Body . String ( ) )
}
2022-05-10 19:48:51 -06:00
server . refresh ( )
2020-08-21 17:02:38 -06:00
2020-10-13 18:33:12 -06:00
if r := hs . TestRequest ( "/content/pategory/2/puzzle.json" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
}
2020-08-21 17:02:38 -06:00
state := StateExport { }
if r := hs . TestRequest ( "/state" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
} else if err := json . Unmarshal ( r . Body . Bytes ( ) , & state ) ; err != nil {
t . Error ( err )
} else if len ( state . PointsLog ) != 1 {
2021-10-20 11:29:55 -06:00
switch v := server . State . ( type ) {
case * State :
log . Print ( v )
}
2022-05-10 19:36:36 -06:00
t . Errorf ( "Points log wrong length. Wanted 1, got %v (length %d)" , state . PointsLog , len ( state . PointsLog ) )
2020-08-21 17:02:38 -06:00
} else if len ( state . Puzzles [ "pategory" ] ) != 2 {
t . Error ( "Didn't unlock next puzzle" )
}
if r := hs . TestRequest ( "/answer" , map [ string ] string { "cat" : "pategory" , "points" : "1" , "answer" : "answer123" } ) ; r . Result ( ) . StatusCode != 200 {
t . Error ( r . Result ( ) )
2021-10-20 11:29:55 -06:00
} else if strings . Contains ( r . Body . String ( ) , "incorrect answer" ) {
// Pernicious intermittent bug
t . Error ( "Incorrect answer that was actually correct" )
for _ , provider := range server . PuzzleProviders {
if mb , ok := provider . ( * Mothballs ) ; ! ok {
t . Error ( "Provider is not a mothball" )
} else {
if cat , ok := mb . getCat ( "pategory" ) ; ! ok {
t . Error ( "opening pategory failed" )
} else if f , err := cat . Open ( "answers.txt" ) ; err != nil {
t . Error ( "opening answers.txt" , err )
} else {
defer f . Close ( )
answersBytes , _ := ioutil . ReadAll ( f )
t . Errorf ( "Correct answers: %#v len %d" , string ( answersBytes ) , len ( answersBytes ) )
}
}
}
t . Error ( "Wrong answer" )
2021-10-13 18:25:27 -06:00
} else if r . Body . String ( ) != ` { "status":"fail","data": { "short":"not accepted","description":"error awarding points: points already awarded to this team in this category"}} ` {
2020-08-21 17:02:38 -06:00
t . Error ( "Unexpected body" , r . Body . String ( ) )
}
2020-08-19 18:01:21 -06:00
}
2020-09-15 15:58:21 -06:00
func TestDevelMemHttpd ( t * testing . T ) {
srv := NewTestServer ( )
{
2022-05-10 19:48:51 -06:00
hs := NewHTTPServer ( "/" , srv . MothServer )
2020-09-15 15:58:21 -06:00
if r := hs . TestRequest ( "/mothballer/pategory.md" , nil ) ; r . Result ( ) . StatusCode != 404 {
t . Error ( "Should have gotten a 404 for mothballer in prod mode" )
}
}
{
srv . Config . Devel = true
2022-05-10 19:48:51 -06:00
hs := NewHTTPServer ( "/" , srv . MothServer )
2020-09-15 15:58:21 -06:00
if r := hs . TestRequest ( "/mothballer/pategory.md" , nil ) ; r . Result ( ) . StatusCode != 500 {
t . Log ( r . Body . String ( ) )
t . Log ( r . Result ( ) )
t . Error ( "Should have given us an internal server error, since category is a mothball" )
}
}
}
func TestDevelFsHttps ( t * testing . T ) {
fs := afero . NewBasePathFs ( afero . NewOsFs ( ) , "testdata" )
transpilerProvider := NewTranspilerProvider ( fs )
srv := NewMothServer ( Configuration { Devel : true } , NewTestTheme ( ) , NewTestState ( ) , transpilerProvider )
hs := NewHTTPServer ( "/" , srv )
if r := hs . TestRequest ( "/mothballer/cat0.mb" , nil ) ; r . Result ( ) . StatusCode != 200 {
t . Log ( r . Body . String ( ) )
t . Log ( r . Result ( ) )
t . Error ( "Didn't get a Mothball" )
}
}