537 lines
12 KiB
Go
537 lines
12 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.andreafazzi.eu/andrea/oef/config"
|
|
"git.andreafazzi.eu/andrea/oef/orm"
|
|
"git.andreafazzi.eu/andrea/oef/renderer"
|
|
"github.com/PuerkitoBio/goquery"
|
|
jwt "github.com/dgrijalva/jwt-go"
|
|
"github.com/gorilla/mux"
|
|
"github.com/remogatto/prettytest"
|
|
)
|
|
|
|
var (
|
|
token string
|
|
handlers *Handlers
|
|
conf *config.ConfigT
|
|
)
|
|
|
|
// Start of setup
|
|
|
|
type testSuite struct {
|
|
prettytest.Suite
|
|
}
|
|
|
|
func login(request *http.Request, handlers *Handlers, username string, password string) (*http.Request, error) {
|
|
tokenString := requestToken(handlers, username, password)
|
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
return []byte(handlers.Config.Keys.JWTSigningKey), nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ctx := request.Context()
|
|
ctx = context.WithValue(ctx, "user", token)
|
|
return request.WithContext(ctx), nil
|
|
|
|
}
|
|
|
|
func requestToken(handlers *Handlers, username string, password string) string {
|
|
req, err := http.NewRequest("GET", "/get_token", nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
req.SetBasicAuth(username, password)
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
handlers.GetToken(handlers.Database, []byte(handlers.Config.Keys.JWTSigningKey)).ServeHTTP(rr, req)
|
|
|
|
var data struct {
|
|
Token string
|
|
}
|
|
|
|
if err := json.Unmarshal(rr.Body.Bytes(), &data); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return data.Token
|
|
|
|
}
|
|
|
|
func deleteParticipant(id uint) int {
|
|
req, err := handlers.NewDeleteRequest(&orm.Participant{}, fmt.Sprintf("/participants/%d/delete", id), "html")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
req, err = login(req, handlers, "admin", "admin")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/participants/{id}/delete", handlers.Delete(&orm.Participant{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
return rr.Code
|
|
}
|
|
|
|
func deleteSchool(id uint) int {
|
|
req, err := handlers.NewDeleteRequest(&orm.School{}, fmt.Sprintf("/schools/%d/delete", id), "html")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
req, err = login(req, handlers, "admin", "admin")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/schools/{id}/delete", handlers.Delete(&orm.School{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
return rr.Code
|
|
}
|
|
|
|
func subscribeSchoolAsSchool() (uint, error) {
|
|
form := url.Values{}
|
|
form.Add("Name", "Foo School")
|
|
form.Add("Code", "123456789")
|
|
form.Add("Email", "foo@school.org")
|
|
|
|
req, err := handlers.NewCreateRequest(&orm.School{}, "/schools/create/", "html", "POST", form)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
req, err = login(req, handlers, "subscriber", "subscribe")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/schools/create/", handlers.Create(&orm.School{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusSeeOther {
|
|
return 0, errors.New("Unexpected response code")
|
|
}
|
|
|
|
re := regexp.MustCompile(`/schools/([0-9]+)\?`)
|
|
matches := re.FindStringSubmatch(rr.Header()["Location"][0])
|
|
id, err := strconv.Atoi(matches[1])
|
|
|
|
return uint(id), nil
|
|
}
|
|
|
|
func getIdFromPath(path string) (uint, error) {
|
|
re := regexp.MustCompile(`/[a-z]+/([0-9]+)\?`)
|
|
matches := re.FindStringSubmatch(path)
|
|
id, err := strconv.Atoi(matches[1])
|
|
return uint(id), err
|
|
}
|
|
|
|
func TestRunner(t *testing.T) {
|
|
prettytest.Run(
|
|
t,
|
|
new(testSuite),
|
|
)
|
|
}
|
|
|
|
func (t *testSuite) BeforeAll() {
|
|
|
|
var db *orm.Database
|
|
|
|
conf = new(config.ConfigT)
|
|
|
|
// Load the configuration
|
|
|
|
err := config.ReadFile("testdata/config.yaml", conf)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
conf.LogLevel = config.LOG_LEVEL_DEBUG
|
|
|
|
// Initialize the ORM
|
|
|
|
connected := false
|
|
for !connected {
|
|
var err error
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
db, err = orm.NewDatabase(conf, orm.Models)
|
|
if err != nil {
|
|
log.Print(err)
|
|
continue
|
|
}
|
|
|
|
connected = true
|
|
}
|
|
|
|
db.AutoMigrate()
|
|
|
|
// Initialize the renderers
|
|
|
|
htmlRenderer, err := renderer.NewHTMLRenderer("../templates/")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
renderer := map[string]renderer.Renderer{
|
|
"html": htmlRenderer,
|
|
}
|
|
|
|
conf.Handlers.Permissions = map[string]map[string][]int{
|
|
"administrator": map[string][]int{
|
|
"Contest": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
|
|
"Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
|
|
"School": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
|
|
"Question": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
|
|
"Answer": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
|
|
"Response": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
|
|
},
|
|
|
|
"school": map[string][]int{
|
|
"Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
|
|
"School": []int{PermissionRead, PermissionUpdate},
|
|
},
|
|
|
|
"participant": map[string][]int{
|
|
"Participant": []int{PermissionRead},
|
|
"Response": []int{PermissionUpdate, PermissionRead},
|
|
},
|
|
|
|
"subscriber": map[string][]int{
|
|
"School": []int{PermissionCreate, PermissionRead},
|
|
},
|
|
}
|
|
|
|
conf.Handlers.PathPatterns = DefaultPathPatterns
|
|
conf.Handlers.APIPathPatterns = DefaultAPIPathPatterns
|
|
|
|
handlers = NewHandlers(conf, renderer, db, orm.Models)
|
|
}
|
|
|
|
func (t *testSuite) TestReadAllContests() {
|
|
req, err := handlers.NewReadAllRequest(&orm.Contest{}, "/contests", "html")
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, "admin", "admin")
|
|
t.Nil(err)
|
|
|
|
if !t.Failed() {
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/contests", handlers.ReadAll(&orm.Contest{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusOK, rr.Code)
|
|
|
|
if !t.Failed() {
|
|
doc, err := goquery.NewDocumentFromReader(rr.Body)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
expected := []string{"JUNIOR Contest", "SENIOR Contest"}
|
|
ok := true
|
|
doc.Find(".list-group-item").Each(func(i int, s *goquery.Selection) {
|
|
if !strings.Contains(s.Text(), expected[i]) {
|
|
ok = false
|
|
}
|
|
})
|
|
t.True(ok)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func (t *testSuite) TestReadContest() {
|
|
req, err := handlers.NewReadRequest(&orm.Contest{}, "/contests/1", "html")
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, "admin", "admin")
|
|
t.Nil(err)
|
|
|
|
if !t.Failed() {
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/contests/{id}", handlers.Read(&orm.Contest{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusOK, rr.Code)
|
|
|
|
if !t.Failed() {
|
|
doc, err := goquery.NewDocumentFromReader(rr.Body)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
expected := "JUNIOR Contest"
|
|
ok := true
|
|
doc.Find("h1").Each(func(i int, s *goquery.Selection) {
|
|
if !strings.Contains(s.Text(), expected) {
|
|
ok = false
|
|
}
|
|
})
|
|
t.True(ok)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func (t *testSuite) TestSchoolSubscriptionForm() {
|
|
req, err := handlers.NewCreateRequest(&orm.School{}, "/schools/create/", "html", "GET", nil)
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, "subscriber", "subscribe")
|
|
t.Nil(err)
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/schools/create/", handlers.Create(&orm.School{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusOK, rr.Code)
|
|
|
|
if !t.Failed() {
|
|
doc, err := goquery.NewDocumentFromReader(rr.Body)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
expected := []string{
|
|
"Denominazione dell'istituto",
|
|
"Codice meccanografico",
|
|
"Indirizzo dell'istituto",
|
|
"Regione",
|
|
"Indirizzo email",
|
|
"Nome del referente di sede",
|
|
"Cognome del referente di sede",
|
|
"Nome del responsabile di gara",
|
|
"Cognome del responsabile di gara",
|
|
}
|
|
ok := true
|
|
doc.Find(".control-label").Each(func(i int, s *goquery.Selection) {
|
|
t.Equal(expected[i], s.Text())
|
|
if t.Failed() {
|
|
ok = false
|
|
}
|
|
})
|
|
t.True(ok)
|
|
}
|
|
|
|
}
|
|
|
|
func (t *testSuite) TestSchoolSubscription() {
|
|
form := url.Values{}
|
|
form.Add("Name", "FooSchool")
|
|
form.Add("Code", "123")
|
|
form.Add("Email", "foo@school.org")
|
|
|
|
req, err := handlers.NewCreateRequest(&orm.School{}, "/schools/create/", "html", "POST", form)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, "subscriber", "subscribe")
|
|
t.Nil(err)
|
|
|
|
if !t.Failed() {
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/schools/create/", handlers.Create(&orm.School{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusSeeOther, rr.Code)
|
|
|
|
schoolId, err := getIdFromPath(rr.Header()["Location"][0])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if !t.Failed() {
|
|
doc, err := goquery.NewDocumentFromReader(rr.Body)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
expected := []string{
|
|
"FooSchool",
|
|
"123",
|
|
}
|
|
ok := true
|
|
doc.Find("dd").Each(func(i int, s *goquery.Selection) {
|
|
t.Equal(expected[i], s.Text())
|
|
if t.Failed() {
|
|
ok = false
|
|
}
|
|
})
|
|
t.True(ok)
|
|
}
|
|
|
|
var school orm.School
|
|
err = handlers.Database.DB().First(&school, schoolId).Error
|
|
t.Nil(err)
|
|
|
|
if !t.Failed() {
|
|
var user orm.User
|
|
if err := handlers.Database.DB().First(&user, school.UserID).Error; err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
t.Equal("123", user.Username)
|
|
|
|
form := url.Values{}
|
|
form.Add("Firstname", "Mario")
|
|
form.Add("Lastname", "BROS")
|
|
form.Add("Fiscalcode", "BRSMRE815ZL16")
|
|
form.Add("category_id", "1")
|
|
form.Add("school_id", strconv.Itoa(int(school.ID)))
|
|
|
|
req, err := handlers.NewCreateRequest(&orm.Participant{}, "/participants/create/", "html", "POST", form)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, user.Username, user.Password)
|
|
t.Nil(err)
|
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/participants/create/", handlers.Create(&orm.Participant{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusSeeOther, rr.Code)
|
|
if !t.Failed() {
|
|
participantId, err := getIdFromPath(rr.Header()["Location"][0])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
t.Equal(http.StatusOK, deleteParticipant(participantId))
|
|
}
|
|
|
|
}
|
|
|
|
t.Equal(http.StatusOK, deleteSchool(schoolId))
|
|
}
|
|
|
|
}
|
|
|
|
func (t *testSuite) TestParticipantResponse() {
|
|
form := url.Values{}
|
|
form.Set("Singleresponses.0", "9")
|
|
|
|
req, err := handlers.NewUpdateRequest(&orm.Response{}, "/responses/5/update", "html", "POST", form)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, "RHOMAT9HZ", "9HzXOfJPje")
|
|
t.Nil(err)
|
|
|
|
if !t.Failed() {
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/responses/{id}/update", handlers.Update(&orm.Response{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusSeeOther, rr.Code)
|
|
|
|
if !t.Failed() {
|
|
req, err := handlers.NewReadRequest(&orm.Response{}, "/responses/5", "html")
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, "admin", "admin")
|
|
t.Nil(err)
|
|
|
|
rr = httptest.NewRecorder()
|
|
|
|
router = mux.NewRouter()
|
|
router.Handle("/responses/{id}", handlers.Read(&orm.Response{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusOK, rr.Code)
|
|
|
|
if !t.Failed() {
|
|
doc, err := goquery.NewDocumentFromReader(rr.Body)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
expected := "1"
|
|
ok := false
|
|
doc.Find("dd").Each(func(i int, s *goquery.Selection) {
|
|
if s.Text() == expected {
|
|
ok = true
|
|
}
|
|
})
|
|
t.True(ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func (t *testSuite) TestUserModifier() {
|
|
id, err := subscribeSchoolAsSchool()
|
|
t.Nil(err)
|
|
|
|
req, err := handlers.NewReadRequest(&orm.School{}, fmt.Sprintf("/schools/%d", id), "html")
|
|
t.Nil(err)
|
|
|
|
req, err = login(req, handlers, "admin", "admin")
|
|
t.Nil(err)
|
|
|
|
if !t.Failed() {
|
|
rr := httptest.NewRecorder()
|
|
|
|
router := mux.NewRouter()
|
|
router.Handle("/schools/{id}", handlers.Read(&orm.School{}))
|
|
router.ServeHTTP(rr, req)
|
|
|
|
t.Equal(http.StatusOK, rr.Code)
|
|
|
|
if !t.Failed() {
|
|
doc, err := goquery.NewDocumentFromReader(rr.Body)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
expected := "subscriber[subscriber]"
|
|
ok := false
|
|
doc.Find("dd").Each(func(i int, s *goquery.Selection) {
|
|
if strings.Contains(s.Text(), expected) {
|
|
ok = true
|
|
}
|
|
})
|
|
t.True(ok)
|
|
}
|
|
}
|
|
|
|
t.Equal(http.StatusOK, deleteSchool(id))
|
|
|
|
}
|