mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
- revise testing of dashboard enpoints
- clean up testdata, serializers and responses - add validators for dashboards - revise documentation of dashboard endpoints for swaggo - revise endpoint implementations
This commit is contained in:
parent
e0ae839e96
commit
dab027eef6
9 changed files with 434 additions and 160 deletions
|
@ -2,13 +2,6 @@ package common
|
||||||
|
|
||||||
import "github.com/jinzhu/gorm/dialects/postgres"
|
import "github.com/jinzhu/gorm/dialects/postgres"
|
||||||
|
|
||||||
type DashboardResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Grid int `json:"grid"`
|
|
||||||
ScenarioID uint `json:"scenarioID"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WidgetResponse struct {
|
type WidgetResponse struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -59,14 +52,6 @@ type ResponseMsgSignal struct {
|
||||||
Signal SignalResponse `json:"signal"`
|
Signal SignalResponse `json:"signal"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseMsgDashboards struct {
|
|
||||||
Dashboards []DashboardResponse `json:"dashboards"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseMsgDashboard struct {
|
|
||||||
Dashboard DashboardResponse `json:"dashboard"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseMsgWidgets struct {
|
type ResponseMsgWidgets struct {
|
||||||
Widgets []WidgetResponse `json:"widgets"`
|
Widgets []WidgetResponse `json:"widgets"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,38 +4,6 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dashboard/s Serializers
|
|
||||||
|
|
||||||
type DashboardsSerializer struct {
|
|
||||||
Ctx *gin.Context
|
|
||||||
Dashboards []Dashboard
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *DashboardsSerializer) Response() []DashboardResponse {
|
|
||||||
response := []DashboardResponse{}
|
|
||||||
for _, dashboard := range self.Dashboards {
|
|
||||||
serializer := DashboardSerializer{self.Ctx, dashboard}
|
|
||||||
response = append(response, serializer.Response())
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
type DashboardSerializer struct {
|
|
||||||
Ctx *gin.Context
|
|
||||||
Dashboard
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *DashboardSerializer) Response() DashboardResponse {
|
|
||||||
|
|
||||||
response := DashboardResponse{
|
|
||||||
Name: self.Name,
|
|
||||||
Grid: self.Grid,
|
|
||||||
ScenarioID: self.ScenarioID,
|
|
||||||
ID: self.ID,
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
// Widget/s Serializers
|
// Widget/s Serializers
|
||||||
|
|
||||||
type WidgetsSerializer struct {
|
type WidgetsSerializer struct {
|
||||||
|
|
|
@ -196,14 +196,14 @@ var InSignalCUpdated_response = SignalResponse{
|
||||||
|
|
||||||
// Dashboards
|
// Dashboards
|
||||||
|
|
||||||
var DashboardA = Dashboard{Name: "Dashboard_A", Grid: 15}
|
var DashboardA = Dashboard{
|
||||||
var DashboardA_response = DashboardResponse{ID: 1, Name: DashboardA.Name, Grid: DashboardA.Grid, ScenarioID: DashboardA.ScenarioID}
|
Name: "Dashboard_A",
|
||||||
var DashboardB = Dashboard{Name: "Dashboard_B", Grid: 10}
|
Grid: 15,
|
||||||
var DashboardB_response = DashboardResponse{ID: 2, Name: DashboardB.Name, Grid: DashboardB.Grid, ScenarioID: DashboardB.ScenarioID}
|
}
|
||||||
var DashboardC = Dashboard{Name: "Dashboard_C", Grid: 25}
|
var DashboardB = Dashboard{
|
||||||
var DashboardC_response = DashboardResponse{ID: 3, Name: DashboardC.Name, Grid: DashboardC.Grid, ScenarioID: DashboardC.ScenarioID}
|
Name: "Dashboard_B",
|
||||||
var DashboardCUpdated = Dashboard{Name: "Dashboard_Cupdated", Grid: 24}
|
Grid: 10,
|
||||||
var DashboardCUpdated_response = DashboardResponse{ID: 3, Name: DashboardCUpdated.Name, Grid: DashboardCUpdated.Grid, ScenarioID: DashboardCUpdated.ScenarioID}
|
}
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
|
|
||||||
|
|
|
@ -48,3 +48,11 @@ type ResponseSimulationModels struct {
|
||||||
type ResponseSimulationModel struct {
|
type ResponseSimulationModel struct {
|
||||||
model common.SimulationModel
|
model common.SimulationModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResponseDashboards struct {
|
||||||
|
dashboards []common.Dashboard
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseDashboard struct {
|
||||||
|
dashboard common.Dashboard
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dashboard
|
package dashboard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -23,11 +24,10 @@ func RegisterDashboardEndpoints(r *gin.RouterGroup) {
|
||||||
// @ID getDashboards
|
// @ID getDashboards
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Tags dashboards
|
// @Tags dashboards
|
||||||
// @Success 200 {array} common.DashboardResponse "Array of dashboards to which belong to scenario"
|
// @Success 200 {object} docs.ResponseDashboards "Dashboards to which belong to scenario"
|
||||||
// @Failure 401 "Unauthorized Access"
|
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||||
// @Failure 403 "Access forbidden."
|
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||||
// @Failure 404 "Not found"
|
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||||
// @Failure 500 "Internal server error"
|
|
||||||
// @Param scenarioID query int true "Scenario ID"
|
// @Param scenarioID query int true "Scenario ID"
|
||||||
// @Router /dashboards [get]
|
// @Router /dashboards [get]
|
||||||
func getDashboards(c *gin.Context) {
|
func getDashboards(c *gin.Context) {
|
||||||
|
@ -44,9 +44,8 @@ func getDashboards(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
serializer := common.DashboardsSerializer{c, dab}
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"dashboards": serializer.Response(),
|
"dashboards": dab,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,44 +55,54 @@ func getDashboards(c *gin.Context) {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Tags dashboards
|
// @Tags dashboards
|
||||||
// @Param inputDab body common.ResponseMsgDashboard true "Dashboard to be added incl. ID of Scenario"
|
// @Param inputDab body dashboard.validNewDashboard true "Dashboard to be added incl. ID of Scenario"
|
||||||
// @Success 200 "OK."
|
// @Success 200 {object} docs.ResponseDashboard "Dashboards that was added"
|
||||||
// @Failure 401 "Unauthorized Access"
|
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||||
// @Failure 403 "Access forbidden."
|
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||||
// @Failure 404 "Not found"
|
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||||
// @Failure 500 "Internal server error"
|
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||||
// @Router /dashboards [post]
|
// @Router /dashboards [post]
|
||||||
func addDashboard(c *gin.Context) {
|
func addDashboard(c *gin.Context) {
|
||||||
|
|
||||||
var newDabData common.ResponseMsgDashboard
|
// bind request to JSON
|
||||||
err := c.BindJSON(&newDabData)
|
var req addDashboardRequest
|
||||||
if err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
errormsg := "Bad request. Error binding form data to JSON: " + err.Error()
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": errormsg,
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("%v", err),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var newDab Dashboard
|
// Validate the request
|
||||||
newDab.ID = newDabData.Dashboard.ID
|
if err := req.validate(); err != nil {
|
||||||
newDab.Grid = newDabData.Dashboard.Grid
|
c.JSON(http.StatusUnprocessableEntity, gin.H{
|
||||||
newDab.ScenarioID = newDabData.Dashboard.ScenarioID
|
"success": false,
|
||||||
newDab.Name = newDabData.Dashboard.Name
|
"message": fmt.Sprintf("%v", err),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ok, _ := scenario.CheckPermissions(c, common.Create, "body", int(newDab.ScenarioID))
|
// Create the new dashboard from the request
|
||||||
|
newDashboard := req.createDashboard()
|
||||||
|
|
||||||
|
// Check if user is allowed to modify scenario specified in request
|
||||||
|
ok, _ := scenario.CheckPermissions(c, common.Create, "body", int(newDashboard.ScenarioID))
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// add dashboard to DB and add association to scenario
|
// add dashboard to DB and add association to scenario
|
||||||
err = newDab.addToScenario()
|
err := newDashboard.addToScenario()
|
||||||
if common.ProvideErrorResponse(c, err) == false {
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
common.ProvideErrorResponse(c, err)
|
||||||
"message": "OK.",
|
return
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"dashboard": newDashboard.Dashboard,
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateDashboard godoc
|
// updateDashboard godoc
|
||||||
|
@ -102,37 +111,59 @@ func addDashboard(c *gin.Context) {
|
||||||
// @Tags dashboards
|
// @Tags dashboards
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param inputDab body common.ResponseMsgDashboard true "Dashboard to be updated"
|
// @Param inputDab body dashboard.validUpdatedDashboard true "Dashboard to be updated"
|
||||||
// @Success 200 "OK."
|
// @Success 200 {object} docs.ResponseDashboard "Dashboards that was updated"
|
||||||
// @Failure 401 "Unauthorized Access"
|
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||||
// @Failure 403 "Access forbidden."
|
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||||
// @Failure 404 "Not found"
|
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||||
// @Failure 500 "Internal server error"
|
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||||
// @Param dashboardID path int true "Dashboard ID"
|
// @Param dashboardID path int true "Dashboard ID"
|
||||||
// @Router /dashboards/{dashboardID} [put]
|
// @Router /dashboards/{dashboardID} [put]
|
||||||
func updateDashboard(c *gin.Context) {
|
func updateDashboard(c *gin.Context) {
|
||||||
|
|
||||||
ok, d := CheckPermissions(c, common.Update, "path", -1)
|
ok, oldDashboard := CheckPermissions(c, common.Update, "path", -1)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var modifiedDab common.ResponseMsgDashboard
|
var req updateDashboardRequest
|
||||||
err := c.BindJSON(&modifiedDab)
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
if err != nil {
|
|
||||||
errormsg := "Bad request. Error binding form data to JSON: " + err.Error()
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": errormsg,
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("%v", err),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.update(modifiedDab.Dashboard)
|
// Validate the request
|
||||||
if common.ProvideErrorResponse(c, err) == false {
|
if err := req.validate(); err != nil {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"message": "OK.",
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("%v", err),
|
||||||
})
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
// Create the updatedScenario from oldScenario
|
||||||
|
updatedDashboard, err := req.updatedDashboard(oldDashboard)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("%v", err),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the dashboard in the DB
|
||||||
|
err = oldDashboard.update(updatedDashboard)
|
||||||
|
if err != nil {
|
||||||
|
common.ProvideErrorResponse(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"dashboard": updatedDashboard.Dashboard,
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDashboard godoc
|
// getDashboard godoc
|
||||||
|
@ -140,11 +171,11 @@ func updateDashboard(c *gin.Context) {
|
||||||
// @ID getDashboard
|
// @ID getDashboard
|
||||||
// @Tags dashboards
|
// @Tags dashboards
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} common.DashboardResponse "Requested dashboard."
|
// @Success 200 {object} docs.ResponseDashboard "Dashboards that was requested"
|
||||||
// @Failure 401 "Unauthorized Access"
|
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||||
// @Failure 403 "Access forbidden."
|
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||||
// @Failure 404 "Not found"
|
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||||
// @Failure 500 "Internal server error"
|
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||||
// @Param dashboardID path int true "Dashboard ID"
|
// @Param dashboardID path int true "Dashboard ID"
|
||||||
// @Router /dashboards/{dashboardID} [get]
|
// @Router /dashboards/{dashboardID} [get]
|
||||||
func getDashboard(c *gin.Context) {
|
func getDashboard(c *gin.Context) {
|
||||||
|
@ -154,9 +185,8 @@ func getDashboard(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
serializer := common.DashboardSerializer{c, dab.Dashboard}
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"dashboard": serializer.Response(),
|
"dashboard": dab.Dashboard,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,11 +195,11 @@ func getDashboard(c *gin.Context) {
|
||||||
// @ID deleteDashboard
|
// @ID deleteDashboard
|
||||||
// @Tags dashboards
|
// @Tags dashboards
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 "OK."
|
// @Success 200 {object} docs.ResponseDashboard "Dashboards that was deleted"
|
||||||
// @Failure 401 "Unauthorized Access"
|
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||||
// @Failure 403 "Access forbidden."
|
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||||
// @Failure 404 "Not found"
|
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||||
// @Failure 500 "Internal server error"
|
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||||
// @Param dashboardID path int true "Dashboard ID"
|
// @Param dashboardID path int true "Dashboard ID"
|
||||||
// @Router /dashboards/{dashboardID} [delete]
|
// @Router /dashboards/{dashboardID} [delete]
|
||||||
func deleteDashboard(c *gin.Context) {
|
func deleteDashboard(c *gin.Context) {
|
||||||
|
@ -184,6 +214,6 @@ func deleteDashboard(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"message": "OK.",
|
"dashboard": dab.Dashboard,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package dashboard
|
package dashboard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
|
||||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/scenario"
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/scenario"
|
||||||
)
|
)
|
||||||
|
@ -21,7 +19,7 @@ func (d *Dashboard) ByID(id uint) error {
|
||||||
db := common.GetDB()
|
db := common.GetDB()
|
||||||
err := db.Find(d, id).Error
|
err := db.Find(d, id).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Dashboard with id=%v does not exist", id)
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -46,10 +44,11 @@ func (d *Dashboard) addToScenario() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dashboard) update(modifiedDab common.DashboardResponse) error {
|
func (d *Dashboard) update(modifiedDab Dashboard) error {
|
||||||
|
|
||||||
db := common.GetDB()
|
db := common.GetDB()
|
||||||
|
|
||||||
|
// TODO do we allow to update scenarioID here as well?
|
||||||
err := db.Model(d).Updates(map[string]interface{}{
|
err := db.Model(d).Updates(map[string]interface{}{
|
||||||
"Name": modifiedDab.Name,
|
"Name": modifiedDab.Name,
|
||||||
"Grid": modifiedDab.Grid,
|
"Grid": modifiedDab.Grid,
|
||||||
|
|
|
@ -17,7 +17,10 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, dabIDSource string,
|
||||||
|
|
||||||
err := common.ValidateRole(c, common.ModelDashboard, operation)
|
err := common.ValidateRole(c, common.ModelDashboard, operation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusUnprocessableEntity, "Access denied (role validation failed).")
|
c.JSON(http.StatusUnprocessableEntity, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("Access denied (role validation failed): %v", err),
|
||||||
|
})
|
||||||
return false, dab
|
return false, dab
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,18 +28,18 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, dabIDSource string,
|
||||||
if dabIDSource == "path" {
|
if dabIDSource == "path" {
|
||||||
dabID, err = strconv.Atoi(c.Param("dashboardID"))
|
dabID, err = strconv.Atoi(c.Param("dashboardID"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errormsg := fmt.Sprintf("Bad request. No or incorrect format of dashboardID path parameter")
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": errormsg,
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("Bad request. No or incorrect format of dashboardID path parameter"),
|
||||||
})
|
})
|
||||||
return false, dab
|
return false, dab
|
||||||
}
|
}
|
||||||
} else if dabIDSource == "query" {
|
} else if dabIDSource == "query" {
|
||||||
dabID, err = strconv.Atoi(c.Request.URL.Query().Get("dashboardID"))
|
dabID, err = strconv.Atoi(c.Request.URL.Query().Get("dashboardID"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errormsg := fmt.Sprintf("Bad request. No or incorrect format of dashboardID query parameter")
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": errormsg,
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("Bad request. No or incorrect format of dashboardID query parameter"),
|
||||||
})
|
})
|
||||||
return false, dab
|
return false, dab
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +1,277 @@
|
||||||
package dashboard
|
package dashboard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"fmt"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
|
||||||
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/scenario"
|
||||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user"
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
"github.com/jinzhu/gorm/dialects/postgres"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Test /dashboards endpoints
|
var router *gin.Engine
|
||||||
func TestEndpoints(t *testing.T) {
|
var db *gorm.DB
|
||||||
|
|
||||||
var token string
|
type DashboardRequest struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Grid int `json:"grid,omitempty"`
|
||||||
|
ScenarioID uint `json:"scenarioID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
var myDashboards = []common.DashboardResponse{common.DashboardA_response, common.DashboardB_response}
|
type ScenarioRequest struct {
|
||||||
var msgDashboards = common.ResponseMsgDashboards{Dashboards: myDashboards}
|
Name string `json:"name,omitempty"`
|
||||||
var msgDab = common.ResponseMsgDashboard{Dashboard: common.DashboardC_response}
|
Running bool `json:"running,omitempty"`
|
||||||
var msgDabupdated = common.ResponseMsgDashboard{Dashboard: common.DashboardCUpdated_response}
|
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
db := common.DummyInitDB()
|
func addScenario(token string) (scenarioID uint) {
|
||||||
|
|
||||||
|
// POST $newScenario
|
||||||
|
newScenario := ScenarioRequest{
|
||||||
|
Name: common.ScenarioA.Name,
|
||||||
|
Running: common.ScenarioA.Running,
|
||||||
|
StartParameters: common.ScenarioA.StartParameters,
|
||||||
|
}
|
||||||
|
_, resp, _ := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
|
||||||
|
|
||||||
|
// Read newScenario's ID from the response
|
||||||
|
newScenarioID, _ := common.GetResponseID(resp)
|
||||||
|
|
||||||
|
return uint(newScenarioID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
|
||||||
|
db = common.DummyInitDB()
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
common.DummyPopulateDB(db)
|
|
||||||
|
|
||||||
router := gin.Default()
|
router = gin.Default()
|
||||||
api := router.Group("/api")
|
api := router.Group("/api")
|
||||||
|
|
||||||
// All endpoints require authentication except when someone wants to
|
|
||||||
// login (POST /authenticate)
|
|
||||||
user.RegisterAuthenticate(api.Group("/authenticate"))
|
user.RegisterAuthenticate(api.Group("/authenticate"))
|
||||||
|
|
||||||
api.Use(user.Authentication(true))
|
api.Use(user.Authentication(true))
|
||||||
|
|
||||||
RegisterDashboardEndpoints(api.Group("/dashboards"))
|
RegisterDashboardEndpoints(api.Group("/dashboards"))
|
||||||
|
// scenario endpoints required here to first add a scenario to the DB
|
||||||
|
// that can be associated with a new dashboard
|
||||||
|
scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
|
||||||
|
|
||||||
credjson, _ := json.Marshal(common.CredUser)
|
os.Exit(m.Run())
|
||||||
msgOKjson, _ := json.Marshal(common.MsgOK)
|
}
|
||||||
msgDashboardsjson, _ := json.Marshal(msgDashboards)
|
|
||||||
msgDabjson, _ := json.Marshal(msgDab)
|
|
||||||
msgDabupdatedjson, _ := json.Marshal(msgDabupdated)
|
|
||||||
|
|
||||||
token = common.AuthenticateForTest(t, router, "/api/authenticate", "POST", credjson, 200)
|
func TestAddDashboard(t *testing.T) {
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
// test GET dashboards
|
// authenticate as normal user
|
||||||
common.TestEndpoint(t, router, token, "/api/dashboards?scenarioID=1", "GET", nil, 200, msgDashboardsjson)
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// test POST dashboards
|
scenarioID := addScenario(token)
|
||||||
common.TestEndpoint(t, router, token, "/api/dashboards", "POST", msgDabjson, 200, msgOKjson)
|
|
||||||
|
|
||||||
// test GET dashboards/:dashboardID to check if previous POST worked correctly
|
// test POST dashboards/ $newDashboard
|
||||||
common.TestEndpoint(t, router, token, "/api/dashboards/3", "GET", nil, 200, msgDabjson)
|
newDashboard := DashboardRequest{
|
||||||
|
Name: common.DashboardA.Name,
|
||||||
|
Grid: common.DashboardA.Grid,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/dashboards", "POST", common.KeyModels{"dashboard": newDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// test PUT dashboards/:dashboardID
|
// Compare POST's response with the newDashboard
|
||||||
common.TestEndpoint(t, router, token, "/api/dashboards/3", "PUT", msgDabupdatedjson, 200, msgOKjson)
|
err = common.CompareResponse(resp, common.KeyModels{"dashboard": newDashboard})
|
||||||
common.TestEndpoint(t, router, token, "/api/dashboards/3", "GET", nil, 200, msgDabupdatedjson)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// test DELETE dashboards/:dashboardID
|
// Read newDashboard's ID from the response
|
||||||
common.TestEndpoint(t, router, token, "/api/dashboards/3", "DELETE", nil, 200, msgOKjson)
|
newDashbaordID, err := common.GetResponseID(resp)
|
||||||
common.TestEndpoint(t, router, token, "/api/dashboards?scenarioID=1", "GET", nil, 200, msgDashboardsjson)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// TODO add testing for other return codes
|
// Get the newDashboard
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards/%v", newDashbaordID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare GET's response with the newDashboard
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"dashboard": newDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try to POST a malformed dashboard
|
||||||
|
// Required fields are missing
|
||||||
|
malformedNewDashboard := DashboardRequest{
|
||||||
|
Name: "ThisIsAMalformedDashboard",
|
||||||
|
}
|
||||||
|
// this should NOT work and return a unprocessable entity 442 status code
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
"/api/dashboards", "POST", common.KeyModels{"dashboard": malformedNewDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateDashboard(t *testing.T) {
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
scenarioID := addScenario(token)
|
||||||
|
|
||||||
|
// test POST dashboards/ $newDashboard
|
||||||
|
newDashboard := DashboardRequest{
|
||||||
|
Name: common.DashboardA.Name,
|
||||||
|
Grid: common.DashboardA.Grid,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/dashboards", "POST", common.KeyModels{"dashboard": newDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Read newDashboard's ID from the response
|
||||||
|
newDashbaordID, err := common.GetResponseID(resp)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
updatedDashboard := DashboardRequest{
|
||||||
|
Name: common.DashboardB.Name,
|
||||||
|
Grid: common.DashboardB.Grid,
|
||||||
|
}
|
||||||
|
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards/%v", newDashbaordID), "PUT", common.KeyModels{"dashboard": updatedDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare PUT's response with the updatedDashboard
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"dashboard": updatedDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Get the updatedDashboard
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards/%v", newDashbaordID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare GET's response with the updatedDashboard
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"dashboard": updatedDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try to update a dashboard that does not exist (should return not found 404 status code)
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards/%v", newDashbaordID+1), "PUT", common.KeyModels{"dashboard": updatedDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteDashboard(t *testing.T) {
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
scenarioID := addScenario(token)
|
||||||
|
fmt.Println(scenarioID)
|
||||||
|
|
||||||
|
// test POST dashboards/ $newDashboard
|
||||||
|
newDashboard := DashboardRequest{
|
||||||
|
Name: common.DashboardA.Name,
|
||||||
|
Grid: common.DashboardA.Grid,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/dashboards", "POST", common.KeyModels{"dashboard": newDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Read newDashboard's ID from the response
|
||||||
|
newDashbaordID, err := common.GetResponseID(resp)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Count the number of all the dashboards returned for scenario
|
||||||
|
initialNumber, err := common.LengthOfResponse(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards?scenarioID=%v", scenarioID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Delete the added newDashboard
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards/%v", newDashbaordID), "DELETE", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare DELETE's response with the newDashboard
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"dashboard": newDashboard})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Again count the number of all the dashboards returned for scenario
|
||||||
|
finalNumber, err := common.LengthOfResponse(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards?scenarioID=%v", scenarioID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, finalNumber, initialNumber-1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAllDashboardsOfScenario(t *testing.T) {
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
scenarioID := addScenario(token)
|
||||||
|
fmt.Println(scenarioID)
|
||||||
|
|
||||||
|
// Count the number of all the dashboards returned for scenario
|
||||||
|
initialNumber, err := common.LengthOfResponse(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards?scenarioID=%v", scenarioID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// test POST dashboards/ $newDashboard
|
||||||
|
newDashboardA := DashboardRequest{
|
||||||
|
Name: common.DashboardA.Name,
|
||||||
|
Grid: common.DashboardA.Grid,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/dashboards", "POST", common.KeyModels{"dashboard": newDashboardA})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// POST a second dashboard for the same scenario
|
||||||
|
newDashboardB := DashboardRequest{
|
||||||
|
Name: common.DashboardB.Name,
|
||||||
|
Grid: common.DashboardB.Grid,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
}
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
"/api/dashboards", "POST", common.KeyModels{"dashboard": newDashboardB})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Count again the number of all the dashboards returned for scenario
|
||||||
|
finalNumber, err := common.LengthOfResponse(router, token,
|
||||||
|
fmt.Sprintf("/api/dashboards?scenarioID=%v", scenarioID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, initialNumber+2, finalNumber)
|
||||||
|
}
|
||||||
|
|
69
routes/dashboard/dashboard_validators.go
Normal file
69
routes/dashboard/dashboard_validators.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package dashboard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
var validate *validator.Validate
|
||||||
|
|
||||||
|
type validNewDashboard struct {
|
||||||
|
Name string `form:"Name" validate:"required"`
|
||||||
|
Grid int `form:"Grid" validate:"required"`
|
||||||
|
ScenarioID uint `form:"ScenarioID" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type validUpdatedDashboard struct {
|
||||||
|
Name string `form:"Name" validate:"omitempty"`
|
||||||
|
Grid int `form:"Grid" validate:"omitempty"`
|
||||||
|
ScenarioID uint `form:"ScenarioID" validate:"omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type addDashboardRequest struct {
|
||||||
|
validNewDashboard `json:"dashboard"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type updateDashboardRequest struct {
|
||||||
|
validUpdatedDashboard `json:"dashboard"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *addDashboardRequest) validate() error {
|
||||||
|
validate = validator.New()
|
||||||
|
errs := validate.Struct(r)
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *validUpdatedDashboard) validate() error {
|
||||||
|
validate = validator.New()
|
||||||
|
errs := validate.Struct(r)
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *addDashboardRequest) createDashboard() Dashboard {
|
||||||
|
var s Dashboard
|
||||||
|
|
||||||
|
s.Name = r.Name
|
||||||
|
s.Grid = r.Grid
|
||||||
|
s.ScenarioID = r.ScenarioID
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *updateDashboardRequest) updatedDashboard(oldDashboard Dashboard) (Dashboard, error) {
|
||||||
|
// Use the old Dashboard as a basis for the updated Dashboard `s`
|
||||||
|
s := oldDashboard
|
||||||
|
|
||||||
|
if r.Name != "" {
|
||||||
|
s.Name = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Grid != 0 {
|
||||||
|
s.Grid = r.Grid
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.ScenarioID != 0 {
|
||||||
|
// TODO do we allow this case?
|
||||||
|
//s.ScenarioID = r.ScenarioID
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue