VILLASweb-backend-go/common/utilities.go
smavros b9d78a3823 Improves NewTestEndpoint():
When the HTTP code check is failing (non-200 message) the response
    body is printed so the failure can be identified from the test
    information.
2019-08-13 11:35:03 +02:00

241 lines
6.7 KiB
Go

package common
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/nsf/jsondiff"
"github.com/stretchr/testify/assert"
)
const UserIDCtx = "user_id"
const UserRoleCtx = "user_role"
func ProvideErrorResponse(c *gin.Context, err error) bool {
if err != nil {
if err == gorm.ErrRecordNotFound {
errormsg := "Record not Found in DB: " + err.Error()
c.JSON(http.StatusNotFound, gin.H{
"error": errormsg,
})
} else {
errormsg := "Error on DB Query or transaction: " + err.Error()
c.JSON(http.StatusInternalServerError, gin.H{
"error": errormsg,
})
}
return true // Error
}
return false // No error
}
func LengthOfResponse(router *gin.Engine, token string, url string,
method string, body []byte) (int, error) {
w := httptest.NewRecorder()
if body != nil {
req, _ := http.NewRequest(method, url, bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req)
} else {
req, _ := http.NewRequest(method, url, nil)
req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req)
}
// Convert the response in array of bytes
responseBytes := []byte(w.Body.String())
// First we are trying to unmarshal the response into an array of
// general type variables ([]interface{}). If this fails we will try
// to unmarshal into a single general type variable (interface{}).
// If that also fails we will return -1.
// Response might be array of objects
var arrayResponse map[string][]interface{}
err := json.Unmarshal(responseBytes, &arrayResponse)
if err == nil {
// Get an arbitrary key from tha map. The only key (entry) of
// course is the model's name. With that trick we do not have to
// pass the higher level key as argument.
for arbitrary_key := range arrayResponse {
return len(arrayResponse[arbitrary_key]), nil
}
}
// Response might be a single object
var singleResponse map[string]interface{}
err = json.Unmarshal(responseBytes, &singleResponse)
if err == nil {
return 1, nil
}
// Failed to identify response. It means we got a different HTTP
// code than 200.
return 0, fmt.Errorf("Length of response cannot be detected")
}
func NewTestEndpoint(router *gin.Engine, token string, url string,
method string, requestBody interface{}, expected_code int,
expectedResponse interface{}) error {
w := httptest.NewRecorder()
// Marshal the HTTP request body
body, err := json.Marshal(requestBody)
if err != nil {
return fmt.Errorf("Failed to marshal reqeust body: %v", err)
}
if body != nil {
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil {
return fmt.Errorf("Failed to create new request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req)
} else {
req, err := http.NewRequest(method, url, nil)
if err != nil {
return fmt.Errorf("Failed to create new request: %v", err)
}
req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req)
}
// Check the return HTTP Code
if w.Code != expected_code {
return fmt.Errorf("HTTP Code: Expected \"%v\". Got \"%v\".\n"+
"Response message:\n%v", expected_code, w.Code, w.Body.String())
}
// Serialize expected response
expectedBytes, err := json.Marshal(expectedResponse)
if err != nil {
return fmt.Errorf("Failed to marshal epxected response: %v", err)
}
// Check the response
opts := jsondiff.DefaultConsoleOptions()
diff, _ := jsondiff.Compare(w.Body.Bytes(), expectedBytes, &opts)
if diff.String() != "FullMatch" && diff.String() != "SupersetMatch" {
return fmt.Errorf("Response: Expected \"%v\". Got \"%v\".",
"(FullMatch OR SupersetMatch)", diff.String())
}
return nil
}
func TestEndpoint(t *testing.T, router *gin.Engine, token string, url string, method string, body []byte, expected_code int, expected_response []byte) {
w := httptest.NewRecorder()
if body != nil {
req, _ := http.NewRequest(method, url, bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req)
} else {
req, _ := http.NewRequest(method, url, nil)
req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req)
}
assert.Equal(t, expected_code, w.Code)
//fmt.Println("Actual:", w.Body.String())
//fmt.Println("Expected: ", string(expected_response))
opts := jsondiff.DefaultConsoleOptions()
diff, _ := jsondiff.Compare(w.Body.Bytes(), expected_response, &opts)
assert.Equal(t, "FullMatch", diff.String())
}
func NewAuthenticateForTest(router *gin.Engine, url string,
method string, credentials interface{}, expected_code int) (string,
error) {
w := httptest.NewRecorder()
// Marshal credentials
body, err := json.Marshal(credentials)
if err != nil {
return "", fmt.Errorf("Failed to marshal credentials: %v", err)
}
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil {
return "", fmt.Errorf("Faile to create new request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
// Check the return HTTP Code
if w.Code != expected_code {
return "", fmt.Errorf("HTTP Code: Expected \"%v\". Got \"%v\".",
expected_code, w.Code)
}
var body_data map[string]interface{}
// Get the response
err = json.Unmarshal([]byte(w.Body.String()), &body_data)
if err != nil {
return "", err
}
// Check the response
success := body_data["success"].(bool)
if !success {
fmt.Println("Authentication not successful: ", body_data["message"])
return "", fmt.Errorf("Authentication unsuccessful!")
}
// Return the token and nil error
return body_data["token"].(string), nil
}
func AuthenticateForTest(t *testing.T, router *gin.Engine, url string, method string, body []byte, expected_code int) string {
w := httptest.NewRecorder()
req, _ := http.NewRequest(method, url, bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, expected_code, w.Code)
var body_data map[string]interface{}
err := json.Unmarshal([]byte(w.Body.String()), &body_data)
if err != nil {
panic(err)
}
success := body_data["success"].(bool)
if !success {
fmt.Println("Authentication not successful: ", body_data["message"])
panic(-1)
}
fmt.Println(w.Body.String())
return body_data["token"].(string)
}
// Read the parameter with name paramName from the gin Context and
// return it as uint variable
func UintParamFromCtx(c *gin.Context, paramName string) (uint, error) {
param, err := strconv.Atoi(c.Param(paramName))
return uint(param), err
}