golang-lib/web/webtest/main.go

184 lines
3.9 KiB
Go

package webtest
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"github.com/gin-gonic/gin"
"dev.sum7.eu/genofire/golang-lib/database"
"dev.sum7.eu/genofire/golang-lib/mailer"
"dev.sum7.eu/genofire/golang-lib/web"
)
var (
// DBConnection - url to database on setting up default WebService for webtest
DBConnection = "user=root password=root dbname=defaultdb host=localhost port=26257 sslmode=disable"
)
// Option to configure TestServer
type Option struct {
ReRun bool
DBSetup func(db *database.Database)
ModuleLoader web.ModuleRegisterFunc
}
type testServer struct {
DB *database.Database
Mails chan *mailer.TestingMail
Close func()
gin *gin.Engine
WS *web.Service
lastCookies []*http.Cookie
}
// Login Request format (maybe just internal usage)
type Login struct {
Username string `json:"username"`
Password string `json:"password"`
}
// New starts WebService for testing
func New(modules web.ModuleRegisterFunc) (*testServer, error) {
return NewWithOption(Option{ModuleLoader: modules})
}
// NewWithDBSetup allows to reconfigure before ReRun the database - e.g. for adding Migration-Steps
func NewWithDBSetup(modules web.ModuleRegisterFunc, dbCall func(db *database.Database)) (*testServer, error) {
return NewWithOption(Option{
ReRun: true,
DBSetup: dbCall,
ModuleLoader: modules,
})
}
// NewWithOption allows to configure WebService for testing
func NewWithOption(option Option) (*testServer, error) {
// db setup
dbConfig := database.Database{
Connection: DBConnection,
Testdata: true,
Debug: false,
LogLevel: 0,
}
if option.DBSetup != nil {
option.DBSetup(&dbConfig)
}
var err error
if option.ReRun {
err = dbConfig.ReRun()
} else {
err = dbConfig.Run()
}
if err != nil && err != database.ErrNothingToMigrate {
return nil, err
}
if dbConfig.DB == nil {
return nil, database.ErrNotConnected
}
// api setup
gin.EnableJsonDecoderDisallowUnknownFields()
gin.SetMode(gin.TestMode)
mock, mail := mailer.NewFakeServer()
err = mail.Setup()
if err != nil {
return nil, err
}
ws := &web.Service{
DB: dbConfig.DB,
Mailer: mail,
}
ws.ModuleRegister(option.ModuleLoader)
ws.Session.Name = "mysession"
ws.Session.Secret = "hidden"
r := gin.Default()
ws.LoadSession(r)
ws.Bind(r)
return &testServer{
DB: &dbConfig,
Mails: mock.Mails,
Close: mock.Close,
gin: r,
WS: ws,
}, nil
}
// DatabaseForget, to run a test without a database
func (s *testServer) DatabaseForget() {
s.WS.DB = nil
s.DB = nil
}
// Request sends a request to webtest WebService
func (s *testServer) Request(method, url string, body interface{}, expectCode int, jsonObj interface{}) error {
var jsonBody io.Reader
if body != nil {
if strBody, ok := body.(string); ok {
jsonBody = strings.NewReader(strBody)
} else {
jsonBodyArray, err := json.Marshal(body)
if err != nil {
return err
}
jsonBody = bytes.NewBuffer(jsonBodyArray)
}
}
req, err := http.NewRequest(method, url, jsonBody)
if err != nil {
return err
}
if len(s.lastCookies) > 0 {
for _, c := range s.lastCookies {
req.AddCookie(c)
}
}
w := httptest.NewRecorder()
s.gin.ServeHTTP(w, req)
// valid statusCode
if expectCode != w.Code {
return fmt.Errorf("wrong status code, body: %v", w.Body)
}
if jsonObj != nil {
// fetch JSON
err = json.NewDecoder(w.Body).Decode(jsonObj)
if err != nil {
return err
}
}
result := w.Result()
if result != nil {
cookies := result.Cookies()
if len(cookies) > 0 {
s.lastCookies = cookies
}
}
return nil
}
// Login to API by send request
func (s *testServer) Login(login Login) error {
// POST: correct login
return s.Request(http.MethodPost, "/api/v1/auth/login", &login, http.StatusOK, nil)
}
// TestLogin to API by default login data
func (s *testServer) TestLogin() error {
return s.Login(Login{
Username: "admin",
Password: "CHANGEME",
})
}