mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
- revise simulation model testing
- add validators for simulation model endpoints - revise endpoint implementations and fix responses of simulation models - clean up testdata, serializers and responses for simulation models - change default values of output length and input length of signal mappings to 0
This commit is contained in:
parent
9c809e526a
commit
4914af6c47
10 changed files with 526 additions and 221 deletions
|
@ -53,9 +53,9 @@ type SimulationModel struct {
|
||||||
// Name of simulation model
|
// Name of simulation model
|
||||||
Name string `json:"name" gorm:"not null"`
|
Name string `json:"name" gorm:"not null"`
|
||||||
// Number of output signals
|
// Number of output signals
|
||||||
OutputLength int `json:"outputLength" gorm:"default:1"`
|
OutputLength int `json:"outputLength" gorm:"default:0"`
|
||||||
// Number of input signals
|
// Number of input signals
|
||||||
InputLength int `json:"inputLength" gorm:"default:1"`
|
InputLength int `json:"inputLength" gorm:"default:0"`
|
||||||
// Start parameters of simulation model as JSON
|
// Start parameters of simulation model as JSON
|
||||||
StartParameters postgres.Jsonb `json:"startParameters"`
|
StartParameters postgres.Jsonb `json:"startParameters"`
|
||||||
// ID of Scenario to which simulation model belongs
|
// ID of Scenario to which simulation model belongs
|
||||||
|
|
|
@ -2,16 +2,6 @@ package common
|
||||||
|
|
||||||
import "github.com/jinzhu/gorm/dialects/postgres"
|
import "github.com/jinzhu/gorm/dialects/postgres"
|
||||||
|
|
||||||
type SimulationModelResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
OutputLength int `json:"outputLength"`
|
|
||||||
InputLength int `json:"inputLength"`
|
|
||||||
ScenarioID uint `json:"scenarioID"`
|
|
||||||
SimulatorID uint `json:"simulatorID"`
|
|
||||||
StartParameters postgres.Jsonb `json:"startParameters"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DashboardResponse struct {
|
type DashboardResponse struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -61,14 +51,6 @@ type ResponseMsg struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseMsgSimulationModels struct {
|
|
||||||
SimulationModels []SimulationModelResponse `json:"models"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseMsgSimulationModel struct {
|
|
||||||
SimulationModel SimulationModelResponse `json:"model"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseMsgSignals struct {
|
type ResponseMsgSignals struct {
|
||||||
Signals []SignalResponse `json:"signals"`
|
Signals []SignalResponse `json:"signals"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,40 +4,6 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Model/s Serializers
|
|
||||||
|
|
||||||
type SimulationModelsSerializer struct {
|
|
||||||
Ctx *gin.Context
|
|
||||||
SimulationModels []SimulationModel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *SimulationModelsSerializer) Response() []SimulationModelResponse {
|
|
||||||
response := []SimulationModelResponse{}
|
|
||||||
for _, simulationmodel := range self.SimulationModels {
|
|
||||||
serializer := SimulationModelSerializer{self.Ctx, simulationmodel}
|
|
||||||
response = append(response, serializer.Response())
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
type SimulationModelSerializer struct {
|
|
||||||
Ctx *gin.Context
|
|
||||||
SimulationModel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *SimulationModelSerializer) Response() SimulationModelResponse {
|
|
||||||
response := SimulationModelResponse{
|
|
||||||
ID: self.ID,
|
|
||||||
Name: self.Name,
|
|
||||||
OutputLength: self.OutputLength,
|
|
||||||
InputLength: self.InputLength,
|
|
||||||
ScenarioID: self.ScenarioID,
|
|
||||||
SimulatorID: self.SimulatorID,
|
|
||||||
StartParameters: self.StartParameters,
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dashboard/s Serializers
|
// Dashboard/s Serializers
|
||||||
|
|
||||||
type DashboardsSerializer struct {
|
type DashboardsSerializer struct {
|
||||||
|
|
|
@ -84,7 +84,6 @@ var SimulatorB = Simulator{
|
||||||
|
|
||||||
var startParametersA = json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)
|
var startParametersA = json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)
|
||||||
var startParametersB = json.RawMessage(`{"parameter1" : "testValue1B", "parameter2" : "testValue2B", "parameter3" : 43}`)
|
var startParametersB = json.RawMessage(`{"parameter1" : "testValue1B", "parameter2" : "testValue2B", "parameter3" : 43}`)
|
||||||
var startParametersC = json.RawMessage(`{"parameter1" : "testValue1C", "parameter2" : "testValue2C", "parameter3" : 44}`)
|
|
||||||
|
|
||||||
var ScenarioA = Scenario{
|
var ScenarioA = Scenario{
|
||||||
Name: "Scenario_A",
|
Name: "Scenario_A",
|
||||||
|
@ -101,72 +100,14 @@ var ScenarioB = Scenario{
|
||||||
|
|
||||||
var SimulationModelA = SimulationModel{
|
var SimulationModelA = SimulationModel{
|
||||||
Name: "SimulationModel_A",
|
Name: "SimulationModel_A",
|
||||||
OutputLength: 1,
|
|
||||||
InputLength: 1,
|
|
||||||
StartParameters: postgres.Jsonb{startParametersA},
|
StartParameters: postgres.Jsonb{startParametersA},
|
||||||
}
|
}
|
||||||
|
|
||||||
var SimulationModelA_response = SimulationModelResponse{
|
|
||||||
ID: 1,
|
|
||||||
Name: SimulationModelA.Name,
|
|
||||||
InputLength: SimulationModelA.InputLength,
|
|
||||||
OutputLength: SimulationModelA.OutputLength,
|
|
||||||
StartParameters: SimulationModelA.StartParameters,
|
|
||||||
}
|
|
||||||
|
|
||||||
var SimulationModelB = SimulationModel{
|
var SimulationModelB = SimulationModel{
|
||||||
Name: "SimulationModel_B",
|
Name: "SimulationModel_B",
|
||||||
OutputLength: 1,
|
|
||||||
InputLength: 1,
|
|
||||||
StartParameters: postgres.Jsonb{startParametersB},
|
StartParameters: postgres.Jsonb{startParametersB},
|
||||||
}
|
}
|
||||||
|
|
||||||
var SimulationModelB_response = SimulationModelResponse{
|
|
||||||
ID: 2,
|
|
||||||
Name: SimulationModelB.Name,
|
|
||||||
InputLength: SimulationModelB.InputLength,
|
|
||||||
OutputLength: SimulationModelB.OutputLength,
|
|
||||||
StartParameters: SimulationModelB.StartParameters,
|
|
||||||
}
|
|
||||||
|
|
||||||
var SimulationModelC = SimulationModel{
|
|
||||||
Name: "SimulationModel_C",
|
|
||||||
OutputLength: 1,
|
|
||||||
InputLength: 1,
|
|
||||||
StartParameters: postgres.Jsonb{startParametersC},
|
|
||||||
}
|
|
||||||
|
|
||||||
var SimulationModelC_response = SimulationModelResponse{
|
|
||||||
ID: 3,
|
|
||||||
Name: SimulationModelC.Name,
|
|
||||||
InputLength: SimulationModelC.InputLength,
|
|
||||||
OutputLength: SimulationModelC.OutputLength,
|
|
||||||
ScenarioID: SimulationModelC.ScenarioID,
|
|
||||||
SimulatorID: SimulationModelC.SimulatorID,
|
|
||||||
StartParameters: SimulationModelC.StartParameters,
|
|
||||||
}
|
|
||||||
|
|
||||||
var SimulationModelCUpdated = SimulationModel{
|
|
||||||
Name: "SimulationModel_CUpdated",
|
|
||||||
OutputLength: SimulationModelC.OutputLength,
|
|
||||||
InputLength: SimulationModelC.InputLength,
|
|
||||||
ScenarioID: SimulationModelC.ScenarioID,
|
|
||||||
SimulatorID: 2,
|
|
||||||
StartParameters: SimulationModelC.StartParameters,
|
|
||||||
InputMapping: SimulationModelC.InputMapping,
|
|
||||||
OutputMapping: SimulationModelC.OutputMapping,
|
|
||||||
}
|
|
||||||
|
|
||||||
var SimulationModelCUpdated_response = SimulationModelResponse{
|
|
||||||
ID: 3,
|
|
||||||
Name: SimulationModelCUpdated.Name,
|
|
||||||
InputLength: SimulationModelCUpdated.InputLength,
|
|
||||||
OutputLength: SimulationModelCUpdated.OutputLength,
|
|
||||||
ScenarioID: SimulationModelCUpdated.ScenarioID,
|
|
||||||
SimulatorID: SimulationModelCUpdated.SimulatorID,
|
|
||||||
StartParameters: SimulationModelCUpdated.StartParameters,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signals
|
// Signals
|
||||||
|
|
||||||
var OutSignalA = Signal{
|
var OutSignalA = Signal{
|
||||||
|
|
|
@ -152,8 +152,9 @@ func CompareResponse(resp *bytes.Buffer, expected interface{}) error {
|
||||||
}
|
}
|
||||||
// Compare
|
// Compare
|
||||||
opts := jsondiff.DefaultConsoleOptions()
|
opts := jsondiff.DefaultConsoleOptions()
|
||||||
diff, _ := jsondiff.Compare(resp.Bytes(), expectedBytes, &opts)
|
diff, text := jsondiff.Compare(resp.Bytes(), expectedBytes, &opts)
|
||||||
if diff.String() != "FullMatch" && diff.String() != "SupersetMatch" {
|
if diff.String() != "FullMatch" && diff.String() != "SupersetMatch" {
|
||||||
|
fmt.Println(text)
|
||||||
return fmt.Errorf("Response: Expected \"%v\". Got \"%v\".",
|
return fmt.Errorf("Response: Expected \"%v\". Got \"%v\".",
|
||||||
"(FullMatch OR SupersetMatch)", diff.String())
|
"(FullMatch OR SupersetMatch)", diff.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package simulationmodel
|
package simulationmodel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -22,11 +23,10 @@ func RegisterSimulationModelEndpoints(r *gin.RouterGroup) {
|
||||||
// @ID getSimulationModels
|
// @ID getSimulationModels
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Tags models
|
// @Tags models
|
||||||
// @Success 200 {array} common.SimulationModelResponse "Array of models to which belong to scenario"
|
// @Success 200 {object} docs.ResponseSimulationModels "Simulation models 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 /models [get]
|
// @Router /models [get]
|
||||||
func getSimulationModels(c *gin.Context) {
|
func getSimulationModels(c *gin.Context) {
|
||||||
|
@ -43,9 +43,8 @@ func getSimulationModels(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
serializer := common.SimulationModelsSerializer{c, models}
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"models": serializer.Response(),
|
"models": models,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,45 +54,54 @@ func getSimulationModels(c *gin.Context) {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Tags models
|
// @Tags models
|
||||||
// @Param inputSimulationModel body common.ResponseMsgSimulationModel true "Simulation model to be added incl. IDs of scenario and simulator"
|
// @Param inputSimulationModel body simulationmodel.validNewSimulationModel true "Simulation model to be added incl. IDs of scenario and simulator"
|
||||||
// @Success 200 "OK."
|
// @Success 200 {object} docs.ResponseSimulationModel "simulation model 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 /models [post]
|
// @Router /models [post]
|
||||||
func addSimulationModel(c *gin.Context) {
|
func addSimulationModel(c *gin.Context) {
|
||||||
|
|
||||||
var newModelData common.ResponseMsgSimulationModel
|
// Bind the request to JSON
|
||||||
err := c.BindJSON(&newModelData)
|
var req addSimulationModelRequest
|
||||||
|
err := c.ShouldBindJSON(&req)
|
||||||
if 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": "Bad request. Error binding form data to JSON: " + err.Error(),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var newModel SimulationModel
|
// validate the request
|
||||||
newModel.ID = newModelData.SimulationModel.ID
|
if err = req.validate(); err != nil {
|
||||||
newModel.Name = newModelData.SimulationModel.Name
|
c.JSON(http.StatusUnprocessableEntity, gin.H{
|
||||||
newModel.SimulatorID = newModelData.SimulationModel.SimulatorID
|
"success": false,
|
||||||
newModel.ScenarioID = newModelData.SimulationModel.ScenarioID
|
"message": fmt.Sprintf("%v", err),
|
||||||
newModel.StartParameters = newModelData.SimulationModel.StartParameters
|
})
|
||||||
newModel.OutputLength = 0
|
return
|
||||||
newModel.InputLength = 0
|
}
|
||||||
|
|
||||||
ok, _ := scenario.CheckPermissions(c, common.Create, "body", int(newModel.ScenarioID))
|
// Create the new simulation model from the request
|
||||||
|
newSimulationModel := req.createSimulationModel()
|
||||||
|
|
||||||
|
// check access to the scenario
|
||||||
|
ok, _ := scenario.CheckPermissions(c, common.Create, "body", int(newSimulationModel.ScenarioID))
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = newModel.addToScenario()
|
// add the new simulation model to the scenario
|
||||||
if common.ProvideErrorResponse(c, err) == false {
|
err = newSimulationModel.addToScenario()
|
||||||
c.JSON(http.StatusOK, gin.H{
|
if err != nil {
|
||||||
"message": "OK.",
|
common.ProvideErrorResponse(c, err)
|
||||||
})
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"model": newSimulationModel.SimulationModel,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateSimulationModel godoc
|
// updateSimulationModel godoc
|
||||||
|
@ -102,37 +110,61 @@ func addSimulationModel(c *gin.Context) {
|
||||||
// @Tags models
|
// @Tags models
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param inputSimulationModel body common.ResponseMsgSimulationModel true "Simulation model to be updated"
|
// @Param inputSimulationModel body simulationmodel.validUpdatedSimulationModel true "Simulation model to be updated"
|
||||||
// @Success 200 "OK."
|
// @Success 200 {object} docs.ResponseSimulationModel "simulation model 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"
|
||||||
// @Param modelID path int true "Model ID"
|
// @Param modelID path int true "Model ID"
|
||||||
// @Router /models/{modelID} [put]
|
// @Router /models/{modelID} [put]
|
||||||
func updateSimulationModel(c *gin.Context) {
|
func updateSimulationModel(c *gin.Context) {
|
||||||
|
|
||||||
ok, m := CheckPermissions(c, common.Update, "path", -1)
|
ok, oldSimulationModel := CheckPermissions(c, common.Update, "path", -1)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var modifiedModel common.ResponseMsgSimulationModel
|
var req updateSimulationModelRequest
|
||||||
err := c.BindJSON(&modifiedModel)
|
err := c.BindJSON(&req)
|
||||||
if 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": "Bad request. Error binding form data to JSON: " + err.Error(),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.Update(modifiedModel.SimulationModel)
|
// 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 updatedSimulationModel from oldSimulationModel
|
||||||
|
updatedSimulationModel, err := req.updatedSimulationModel(oldSimulationModel)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"message": fmt.Sprintf("%v", err),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, update the simulation model
|
||||||
|
err = oldSimulationModel.Update(updatedSimulationModel)
|
||||||
|
if err != nil {
|
||||||
|
common.ProvideErrorResponse(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"model": updatedSimulationModel.SimulationModel,
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSimulationModel godoc
|
// getSimulationModel godoc
|
||||||
|
@ -140,11 +172,11 @@ func updateSimulationModel(c *gin.Context) {
|
||||||
// @ID getSimulationModel
|
// @ID getSimulationModel
|
||||||
// @Tags models
|
// @Tags models
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} common.SimulationModelResponse "Requested simulation model."
|
// @Success 200 {object} docs.ResponseSimulationModel "simulation model 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 modelID path int true "Model ID"
|
// @Param modelID path int true "Model ID"
|
||||||
// @Router /models/{modelID} [get]
|
// @Router /models/{modelID} [get]
|
||||||
func getSimulationModel(c *gin.Context) {
|
func getSimulationModel(c *gin.Context) {
|
||||||
|
@ -154,9 +186,8 @@ func getSimulationModel(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
serializer := common.SimulationModelSerializer{c, m.SimulationModel}
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"model": serializer.Response(),
|
"model": m.SimulationModel,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,11 +196,11 @@ func getSimulationModel(c *gin.Context) {
|
||||||
// @ID deleteSimulationModel
|
// @ID deleteSimulationModel
|
||||||
// @Tags models
|
// @Tags models
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 "OK."
|
// @Success 200 {object} docs.ResponseSimulationModel "simulation model 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 modelID path int true "Model ID"
|
// @Param modelID path int true "Model ID"
|
||||||
// @Router /models/{modelID} [delete]
|
// @Router /models/{modelID} [delete]
|
||||||
func deleteSimulationModel(c *gin.Context) {
|
func deleteSimulationModel(c *gin.Context) {
|
||||||
|
@ -185,6 +216,6 @@ func deleteSimulationModel(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"message": "OK.",
|
"model": m.SimulationModel,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package simulationmodel
|
package simulationmodel
|
||||||
|
|
||||||
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"
|
||||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/simulator"
|
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/simulator"
|
||||||
|
@ -22,7 +20,7 @@ func (m *SimulationModel) ByID(id uint) error {
|
||||||
db := common.GetDB()
|
db := common.GetDB()
|
||||||
err := db.Find(m, id).Error
|
err := db.Find(m, id).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Simulation Model with id=%v does not exist", id)
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -55,7 +53,7 @@ func (m *SimulationModel) addToScenario() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SimulationModel) Update(modifiedSimulationModel common.SimulationModelResponse) error {
|
func (m *SimulationModel) Update(modifiedSimulationModel SimulationModel) error {
|
||||||
db := common.GetDB()
|
db := common.GetDB()
|
||||||
|
|
||||||
if m.SimulatorID != modifiedSimulationModel.SimulatorID {
|
if m.SimulatorID != modifiedSimulationModel.SimulatorID {
|
||||||
|
@ -82,12 +80,15 @@ func (m *SimulationModel) Update(modifiedSimulationModel common.SimulationModelR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.ScenarioID != modifiedSimulationModel.ScenarioID {
|
||||||
|
// TODO do we allow this case?
|
||||||
|
}
|
||||||
|
|
||||||
err := db.Model(m).Updates(map[string]interface{}{
|
err := db.Model(m).Updates(map[string]interface{}{
|
||||||
"Name": modifiedSimulationModel.Name,
|
"Name": modifiedSimulationModel.Name,
|
||||||
"OutputLength": modifiedSimulationModel.OutputLength,
|
|
||||||
"InputLength": modifiedSimulationModel.InputLength,
|
|
||||||
"StartParameters": modifiedSimulationModel.StartParameters,
|
"StartParameters": modifiedSimulationModel.StartParameters,
|
||||||
"SimulatorID": modifiedSimulationModel.SimulatorID,
|
"SimulatorID": modifiedSimulationModel.SimulatorID,
|
||||||
|
//"ScenarioID": modifiedSimulationModel.ScenarioID,
|
||||||
}).Error
|
}).Error
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -17,7 +17,10 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, modelIDSource strin
|
||||||
|
|
||||||
err := common.ValidateRole(c, common.ModelSimulationModel, operation)
|
err := common.ValidateRole(c, common.ModelSimulationModel, 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, m
|
return false, m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,16 +30,17 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, modelIDSource strin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errormsg := fmt.Sprintf("Bad request. No or incorrect format of modelID path parameter")
|
errormsg := fmt.Sprintf("Bad request. No or incorrect format of modelID path parameter")
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": errormsg,
|
"success": false,
|
||||||
|
"message": errormsg,
|
||||||
})
|
})
|
||||||
return false, m
|
return false, m
|
||||||
}
|
}
|
||||||
} else if modelIDSource == "query" {
|
} else if modelIDSource == "query" {
|
||||||
modelID, err = strconv.Atoi(c.Request.URL.Query().Get("modelID"))
|
modelID, err = strconv.Atoi(c.Request.URL.Query().Get("modelID"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errormsg := fmt.Sprintf("Bad request. No or incorrect format of modelID 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 modelID query parameter"),
|
||||||
})
|
})
|
||||||
return false, m
|
return false, m
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +1,364 @@
|
||||||
package simulationmodel
|
package simulationmodel
|
||||||
|
|
||||||
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/simulator"
|
||||||
"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 /models endpoints
|
var router *gin.Engine
|
||||||
func TestSimulationModelEndpoints(t *testing.T) {
|
var db *gorm.DB
|
||||||
|
|
||||||
var token string
|
type SimulationModelRequest struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
ScenarioID uint `json:"scenarioID,omitempty"`
|
||||||
|
SimulatorID uint `json:"simulatorID,omitempty"`
|
||||||
|
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
var myModels = []common.SimulationModelResponse{common.SimulationModelA_response, common.SimulationModelB_response}
|
type SimulatorRequest struct {
|
||||||
var msgModels = common.ResponseMsgSimulationModels{SimulationModels: myModels}
|
UUID string `json:"uuid,omitempty"`
|
||||||
var msgModel = common.ResponseMsgSimulationModel{SimulationModel: common.SimulationModelC_response}
|
Host string `json:"host,omitempty"`
|
||||||
var msgModelupdated = common.ResponseMsgSimulationModel{SimulationModel: common.SimulationModelCUpdated_response}
|
Modeltype string `json:"modelType,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
Properties postgres.Jsonb `json:"properties,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
db := common.DummyInitDB()
|
type ScenarioRequest struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Running bool `json:"running,omitempty"`
|
||||||
|
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func addScenarioAndSimulator() (scenarioID uint, simulatorID uint) {
|
||||||
|
|
||||||
|
// authenticate as admin
|
||||||
|
token, _ := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.AdminCredentials)
|
||||||
|
|
||||||
|
// POST $newSimulatorA
|
||||||
|
newSimulatorA := SimulatorRequest{
|
||||||
|
UUID: common.SimulatorA.UUID,
|
||||||
|
Host: common.SimulatorA.Host,
|
||||||
|
Modeltype: common.SimulatorA.Modeltype,
|
||||||
|
State: common.SimulatorA.State,
|
||||||
|
Properties: common.SimulatorA.Properties,
|
||||||
|
}
|
||||||
|
_, resp, _ := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/simulators", "POST", common.KeyModels{"simulator": newSimulatorA})
|
||||||
|
|
||||||
|
// Read newSimulator's ID from the response
|
||||||
|
newSimulatorID, _ := common.GetResponseID(resp)
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, _ = common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
|
||||||
|
// 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), uint(newSimulatorID)
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
RegisterSimulationModelEndpoints(api.Group("/models"))
|
RegisterSimulationModelEndpoints(api.Group("/models"))
|
||||||
|
// scenario endpoints required here to first add a scenario to the DB
|
||||||
|
// that can be associated with a new simulation model
|
||||||
|
scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
|
||||||
|
// simulator endpoints required here to first add a simulator to the DB
|
||||||
|
// that can be associated with a new simulation model
|
||||||
|
simulator.RegisterSimulatorEndpoints(api.Group("/simulators"))
|
||||||
|
|
||||||
credjson, _ := json.Marshal(common.CredUser)
|
os.Exit(m.Run())
|
||||||
msgOKjson, _ := json.Marshal(common.MsgOK)
|
}
|
||||||
msgModelsjson, _ := json.Marshal(msgModels)
|
|
||||||
msgModeljson, _ := json.Marshal(msgModel)
|
|
||||||
msgModelupdatedjson, _ := json.Marshal(msgModelupdated)
|
|
||||||
|
|
||||||
token = common.AuthenticateForTest(t, router, "/api/authenticate", "POST", credjson, 200)
|
func TestAddSimulationModel(t *testing.T) {
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
// test GET models
|
// prepare the content of the DB for testing
|
||||||
common.TestEndpoint(t, router, token, "/api/models?scenarioID=1", "GET", nil, 200, msgModelsjson)
|
// by adding a scenario and a simulator to the DB
|
||||||
|
// using the respective endpoints of the API
|
||||||
|
scenarioID, simulatorID := addScenarioAndSimulator()
|
||||||
|
|
||||||
// test POST models
|
// authenticate as normal user
|
||||||
common.TestEndpoint(t, router, token, "/api/models", "POST", msgModeljson, 200, msgOKjson)
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// test GET models/:ModelID to check if previous POST worked correctly
|
// test POST models/ $newSimulationModel
|
||||||
common.TestEndpoint(t, router, token, "/api/models/3", "GET", nil, 200, msgModeljson)
|
newSimulationModel := SimulationModelRequest{
|
||||||
|
Name: common.SimulationModelA.Name,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
SimulatorID: simulatorID,
|
||||||
|
StartParameters: common.SimulationModelA.StartParameters,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/models", "POST", common.KeyModels{"model": newSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// test PUT models/:ModelID
|
// Compare POST's response with the newSimulationModel
|
||||||
common.TestEndpoint(t, router, token, "/api/models/3", "PUT", msgModelupdatedjson, 200, msgOKjson)
|
err = common.CompareResponse(resp, common.KeyModels{"model": newSimulationModel})
|
||||||
common.TestEndpoint(t, router, token, "/api/models/3", "GET", nil, 200, msgModelupdatedjson)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// test DELETE models/:ModelID
|
// Read newSimulationModel's ID from the response
|
||||||
common.TestEndpoint(t, router, token, "/api/models/3", "DELETE", nil, 200, msgOKjson)
|
newSimulationModelID, err := common.GetResponseID(resp)
|
||||||
common.TestEndpoint(t, router, token, "/api/models?scenarioID=1", "GET", nil, 200, msgModelsjson)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// TODO add testing for other return codes
|
// Get the newSimulationModel
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare GET's response with the newSimulationModel
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"model": newSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try to POST a malformed simulation model
|
||||||
|
// Required fields are missing
|
||||||
|
malformedNewSimulationModel := SimulationModelRequest{
|
||||||
|
Name: "ThisIsAMalformedRequest",
|
||||||
|
}
|
||||||
|
// this should NOT work and return a unprocessable entity 442 status code
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
"/api/models", "POST", common.KeyModels{"model": malformedNewSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateSimulationModel(t *testing.T) {
|
||||||
|
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
|
// prepare the content of the DB for testing
|
||||||
|
// by adding a scenario and a simulator to the DB
|
||||||
|
// using the respective endpoints of the API
|
||||||
|
scenarioID, simulatorID := addScenarioAndSimulator()
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// test POST models/ $newSimulationModel
|
||||||
|
newSimulationModel := SimulationModelRequest{
|
||||||
|
Name: common.SimulationModelA.Name,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
SimulatorID: simulatorID,
|
||||||
|
StartParameters: common.SimulationModelA.StartParameters,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/models", "POST", common.KeyModels{"model": newSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Read newSimulationModel's ID from the response
|
||||||
|
newSimulationModelID, err := common.GetResponseID(resp)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
updatedSimulationModel := SimulationModelRequest{
|
||||||
|
Name: common.SimulationModelB.Name,
|
||||||
|
StartParameters: common.SimulationModelB.StartParameters,
|
||||||
|
}
|
||||||
|
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", common.KeyModels{"model": updatedSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare PUT's response with the updatedSimulationModel
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"model": updatedSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Get the updatedSimulationModel
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare GET's response with the updatedSimulationModel
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"model": updatedSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// try to update a simulation model that does not exist (should return not found 404 status code)
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/models/%v", newSimulationModelID+1), "PUT", common.KeyModels{"scenario": updatedSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteSimulationModel(t *testing.T) {
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
|
// prepare the content of the DB for testing
|
||||||
|
// by adding a scenario and a simulator to the DB
|
||||||
|
// using the respective endpoints of the API
|
||||||
|
scenarioID, simulatorID := addScenarioAndSimulator()
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// test POST models/ $newSimulationModel
|
||||||
|
newSimulationModel := SimulationModelRequest{
|
||||||
|
Name: common.SimulationModelA.Name,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
SimulatorID: simulatorID,
|
||||||
|
StartParameters: common.SimulationModelA.StartParameters,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/models", "POST", common.KeyModels{"model": newSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Read newSimulationModel's ID from the response
|
||||||
|
newSimulationModelID, err := common.GetResponseID(resp)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Count the number of all the simulation models returned for scenario
|
||||||
|
initialNumber, err := common.LengthOfResponse(router, token,
|
||||||
|
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Delete the added newSimulationModel
|
||||||
|
code, resp, err = common.NewTestEndpoint(router, token,
|
||||||
|
fmt.Sprintf("/api/models/%v", newSimulationModelID), "DELETE", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Compare DELETE's response with the newSimulationModel
|
||||||
|
err = common.CompareResponse(resp, common.KeyModels{"model": newSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Again count the number of all the simulation models returned
|
||||||
|
finalNumber, err := common.LengthOfResponse(router, token,
|
||||||
|
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, initialNumber-1, finalNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAllSimulationModelsOfScenario(t *testing.T) {
|
||||||
|
common.DropTables(db)
|
||||||
|
common.MigrateModels(db)
|
||||||
|
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||||
|
|
||||||
|
// prepare the content of the DB for testing
|
||||||
|
// by adding a scenario and a simulator to the DB
|
||||||
|
// using the respective endpoints of the API
|
||||||
|
scenarioID, simulatorID := addScenarioAndSimulator()
|
||||||
|
|
||||||
|
// authenticate as normal user
|
||||||
|
token, err := common.NewAuthenticateForTest(router,
|
||||||
|
"/api/authenticate", "POST", common.UserACredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// test POST models/ $newSimulationModel
|
||||||
|
newSimulationModel := SimulationModelRequest{
|
||||||
|
Name: common.SimulationModelA.Name,
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
SimulatorID: simulatorID,
|
||||||
|
StartParameters: common.SimulationModelA.StartParameters,
|
||||||
|
}
|
||||||
|
code, resp, err := common.NewTestEndpoint(router, token,
|
||||||
|
"/api/models", "POST", common.KeyModels{"model": newSimulationModel})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
// Count the number of all the simulation models returned for scenario
|
||||||
|
NumberOfSimulationModels, err := common.LengthOfResponse(router, token,
|
||||||
|
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, NumberOfSimulationModels)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Test /models endpoints
|
||||||
|
//func TestSimulationModelEndpoints(t *testing.T) {
|
||||||
|
//
|
||||||
|
// var token string
|
||||||
|
//
|
||||||
|
// var myModels = []common.SimulationModelResponse{common.SimulationModelA_response, common.SimulationModelB_response}
|
||||||
|
// var msgModels = common.ResponseMsgSimulationModels{SimulationModels: myModels}
|
||||||
|
// var msgModel = common.ResponseMsgSimulationModel{SimulationModel: common.SimulationModelC_response}
|
||||||
|
// var msgModelupdated = common.ResponseMsgSimulationModel{SimulationModel: common.SimulationModelCUpdated_response}
|
||||||
|
//
|
||||||
|
// db := common.DummyInitDB()
|
||||||
|
// defer db.Close()
|
||||||
|
// common.DummyPopulateDB(db)
|
||||||
|
//
|
||||||
|
// router := gin.Default()
|
||||||
|
// api := router.Group("/api")
|
||||||
|
//
|
||||||
|
// // All endpoints require authentication except when someone wants to
|
||||||
|
// // login (POST /authenticate)
|
||||||
|
// user.RegisterAuthenticate(api.Group("/authenticate"))
|
||||||
|
//
|
||||||
|
// api.Use(user.Authentication(true))
|
||||||
|
//
|
||||||
|
// RegisterSimulationModelEndpoints(api.Group("/models"))
|
||||||
|
//
|
||||||
|
// credjson, _ := json.Marshal(common.CredUser)
|
||||||
|
// msgOKjson, _ := json.Marshal(common.MsgOK)
|
||||||
|
// msgModelsjson, _ := json.Marshal(msgModels)
|
||||||
|
// msgModeljson, _ := json.Marshal(msgModel)
|
||||||
|
// msgModelupdatedjson, _ := json.Marshal(msgModelupdated)
|
||||||
|
//
|
||||||
|
// token = common.AuthenticateForTest(t, router, "/api/authenticate", "POST", credjson, 200)
|
||||||
|
//
|
||||||
|
// // test GET models
|
||||||
|
// common.TestEndpoint(t, router, token, "/api/models?scenarioID=1", "GET", nil, 200, msgModelsjson)
|
||||||
|
//
|
||||||
|
// // test POST models
|
||||||
|
// common.TestEndpoint(t, router, token, "/api/models", "POST", msgModeljson, 200, msgOKjson)
|
||||||
|
//
|
||||||
|
// // test GET models/:ModelID to check if previous POST worked correctly
|
||||||
|
// common.TestEndpoint(t, router, token, "/api/models/3", "GET", nil, 200, msgModeljson)
|
||||||
|
//
|
||||||
|
// // test PUT models/:ModelID
|
||||||
|
// common.TestEndpoint(t, router, token, "/api/models/3", "PUT", msgModelupdatedjson, 200, msgOKjson)
|
||||||
|
// common.TestEndpoint(t, router, token, "/api/models/3", "GET", nil, 200, msgModelupdatedjson)
|
||||||
|
//
|
||||||
|
// // test DELETE models/:ModelID
|
||||||
|
// common.TestEndpoint(t, router, token, "/api/models/3", "DELETE", nil, 200, msgOKjson)
|
||||||
|
// common.TestEndpoint(t, router, token, "/api/models?scenarioID=1", "GET", nil, 200, msgModelsjson)
|
||||||
|
//
|
||||||
|
// // TODO add testing for other return codes
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
80
routes/simulationmodel/simulationmodel_validators.go
Normal file
80
routes/simulationmodel/simulationmodel_validators.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
package simulationmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/jinzhu/gorm/dialects/postgres"
|
||||||
|
"github.com/nsf/jsondiff"
|
||||||
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
var validate *validator.Validate
|
||||||
|
|
||||||
|
type validNewSimulationModel struct {
|
||||||
|
Name string `form:"Name" validate:"required"`
|
||||||
|
ScenarioID uint `form:"ScenarioID" validate:"required"`
|
||||||
|
SimulatorID uint `form:"SimulatorID" validate:"required"`
|
||||||
|
StartParameters postgres.Jsonb `form:"StartParameters" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type validUpdatedSimulationModel struct {
|
||||||
|
Name string `form:"Name" validate:"omitempty"`
|
||||||
|
SimulatorID uint `form:"SimulatorID" validate:"omitempty"`
|
||||||
|
StartParameters postgres.Jsonb `form:"StartParameters" validate:"omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type addSimulationModelRequest struct {
|
||||||
|
validNewSimulationModel `json:"model"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type updateSimulationModelRequest struct {
|
||||||
|
validUpdatedSimulationModel `json:"model"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *addSimulationModelRequest) validate() error {
|
||||||
|
validate = validator.New()
|
||||||
|
errs := validate.Struct(r)
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *validUpdatedSimulationModel) validate() error {
|
||||||
|
validate = validator.New()
|
||||||
|
errs := validate.Struct(r)
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *addSimulationModelRequest) createSimulationModel() SimulationModel {
|
||||||
|
var s SimulationModel
|
||||||
|
|
||||||
|
s.Name = r.Name
|
||||||
|
s.ScenarioID = r.ScenarioID
|
||||||
|
s.SimulatorID = r.SimulatorID
|
||||||
|
s.StartParameters = r.StartParameters
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *updateSimulationModelRequest) updatedSimulationModel(oldSimulationModel SimulationModel) (SimulationModel, error) {
|
||||||
|
// Use the old SimulationModel as a basis for the updated Simulation model
|
||||||
|
s := oldSimulationModel
|
||||||
|
|
||||||
|
if r.Name != "" {
|
||||||
|
s.Name = r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.SimulatorID != 0 {
|
||||||
|
s.SimulatorID = r.SimulatorID
|
||||||
|
}
|
||||||
|
|
||||||
|
// only update Params if not empty
|
||||||
|
var emptyJson postgres.Jsonb
|
||||||
|
// Serialize empty json and params
|
||||||
|
emptyJson_ser, _ := json.Marshal(emptyJson)
|
||||||
|
startParams_ser, _ := json.Marshal(r.StartParameters)
|
||||||
|
opts := jsondiff.DefaultConsoleOptions()
|
||||||
|
diff, _ := jsondiff.Compare(emptyJson_ser, startParams_ser, &opts)
|
||||||
|
if diff.String() != "FullMatch" {
|
||||||
|
s.StartParameters = r.StartParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue