mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
revision of simulator package
- move amqp endpoint implementation to amqp package - improve code coverage of simulator testing - remove some unnecessary code from package implementation
This commit is contained in:
parent
75c33c71a1
commit
c0b8a6be80
7 changed files with 126 additions and 95 deletions
61
amqp/amqp_endpoints.go
Normal file
61
amqp/amqp_endpoints.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package amqp
|
||||
|
||||
import (
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/database"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/helper"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/simulator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RegisterAMQPEndpoint(r *gin.RouterGroup) {
|
||||
r.POST("/:simulatorID/action", sendActionToSimulator)
|
||||
}
|
||||
|
||||
// sendActionToSimulator godoc
|
||||
// @Summary Send an action to simulator (only available if backend server is started with -amqp parameter)
|
||||
// @ID sendActionToSimulator
|
||||
// @Tags AMQP
|
||||
// @Produce json
|
||||
// @Param inputAction query string true "Action for simulator"
|
||||
// @Success 200 {object} docs.ResponseError "Action sent successfully"
|
||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Param simulatorID path int true "Simulator ID"
|
||||
// @Router /simulators/{simulatorID}/action [post]
|
||||
func sendActionToSimulator(c *gin.Context) {
|
||||
|
||||
ok, s := simulator.CheckPermissions(c, database.ModelSimulatorAction, database.Update, true)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var actions []Action
|
||||
err := c.BindJSON(&actions)
|
||||
if err != nil {
|
||||
helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
for _, action := range actions {
|
||||
if action.When == 0 {
|
||||
action.When = float32(now.Unix())
|
||||
}
|
||||
|
||||
err = SendActionAMQP(action, s.UUID)
|
||||
if err != nil {
|
||||
helper.InternalServerError(c, "Unable to send actions to simulator: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "OK.",
|
||||
})
|
||||
}
|
|
@ -1,12 +1,9 @@
|
|||
package simulator
|
||||
|
||||
import (
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/amqp"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/helper"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/database"
|
||||
)
|
||||
|
@ -18,10 +15,6 @@ func RegisterSimulatorEndpoints(r *gin.RouterGroup) {
|
|||
r.GET("/:simulatorID", getSimulator)
|
||||
r.DELETE("/:simulatorID", deleteSimulator)
|
||||
r.GET("/:simulatorID/models", getModelsOfSimulator)
|
||||
// register action endpoint only if AMQP client is used
|
||||
if database.WITH_AMQP == true {
|
||||
r.POST("/:simulatorID/action", sendActionToSimulator)
|
||||
}
|
||||
}
|
||||
|
||||
// getSimulators godoc
|
||||
|
@ -36,19 +29,15 @@ func RegisterSimulatorEndpoints(r *gin.RouterGroup) {
|
|||
// @Router /simulators [get]
|
||||
func getSimulators(c *gin.Context) {
|
||||
|
||||
ok, _ := checkPermissions(c, database.ModelSimulator, database.Read, false)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// Checking permission is not required here since READ access is independent of user's role
|
||||
|
||||
db := database.GetDB()
|
||||
var simulators []database.Simulator
|
||||
err := db.Order("ID asc").Find(&simulators).Error
|
||||
if helper.DBError(c, err) {
|
||||
return
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"simulators": simulators})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"simulators": simulators})
|
||||
}
|
||||
|
||||
// addSimulator godoc
|
||||
|
@ -66,7 +55,7 @@ func getSimulators(c *gin.Context) {
|
|||
// @Router /simulators [post]
|
||||
func addSimulator(c *gin.Context) {
|
||||
|
||||
ok, _ := checkPermissions(c, database.ModelSimulator, database.Create, false)
|
||||
ok, _ := CheckPermissions(c, database.ModelSimulator, database.Create, false)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -89,12 +78,10 @@ func addSimulator(c *gin.Context) {
|
|||
|
||||
// Save new simulator to DB
|
||||
err = newSimulator.save()
|
||||
if err != nil {
|
||||
helper.DBError(c, err)
|
||||
return
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"simulator": newSimulator.Simulator})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"simulator": newSimulator.Simulator})
|
||||
}
|
||||
|
||||
// updateSimulator godoc
|
||||
|
@ -113,7 +100,7 @@ func addSimulator(c *gin.Context) {
|
|||
// @Router /simulators/{simulatorID} [put]
|
||||
func updateSimulator(c *gin.Context) {
|
||||
|
||||
ok, oldSimulator := checkPermissions(c, database.ModelSimulator, database.Update, true)
|
||||
ok, oldSimulator := CheckPermissions(c, database.ModelSimulator, database.Update, true)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -132,21 +119,14 @@ func updateSimulator(c *gin.Context) {
|
|||
}
|
||||
|
||||
// Create the updatedSimulator from oldSimulator
|
||||
updatedSimulator, err := req.updatedSimulator(oldSimulator)
|
||||
if err != nil {
|
||||
helper.BadRequestError(c, err.Error())
|
||||
return
|
||||
}
|
||||
updatedSimulator := req.updatedSimulator(oldSimulator)
|
||||
|
||||
// Finally update the simulator in the DB
|
||||
err = oldSimulator.update(updatedSimulator)
|
||||
if err != nil {
|
||||
helper.DBError(c, err)
|
||||
return
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"simulator": updatedSimulator.Simulator})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"simulator": updatedSimulator.Simulator})
|
||||
|
||||
}
|
||||
|
||||
// getSimulator godoc
|
||||
|
@ -163,7 +143,7 @@ func updateSimulator(c *gin.Context) {
|
|||
// @Router /simulators/{simulatorID} [get]
|
||||
func getSimulator(c *gin.Context) {
|
||||
|
||||
ok, s := checkPermissions(c, database.ModelSimulator, database.Read, true)
|
||||
ok, s := CheckPermissions(c, database.ModelSimulator, database.Read, true)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -185,18 +165,17 @@ func getSimulator(c *gin.Context) {
|
|||
// @Router /simulators/{simulatorID} [delete]
|
||||
func deleteSimulator(c *gin.Context) {
|
||||
|
||||
ok, s := checkPermissions(c, database.ModelSimulator, database.Delete, true)
|
||||
ok, s := CheckPermissions(c, database.ModelSimulator, database.Delete, true)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Delete the simulator
|
||||
err := s.delete()
|
||||
if helper.DBError(c, err) {
|
||||
return
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"simulator": s.Simulator})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"simulator": s.Simulator})
|
||||
}
|
||||
|
||||
// getModelsOfSimulator godoc
|
||||
|
@ -213,63 +192,15 @@ func deleteSimulator(c *gin.Context) {
|
|||
// @Router /simulators/{simulatorID}/models [get]
|
||||
func getModelsOfSimulator(c *gin.Context) {
|
||||
|
||||
ok, s := checkPermissions(c, database.ModelSimulator, database.Read, true)
|
||||
ok, s := CheckPermissions(c, database.ModelSimulator, database.Read, true)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// get all associated simulation models
|
||||
allModels, _, err := s.getModels()
|
||||
if helper.DBError(c, err) {
|
||||
return
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"models": allModels})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"models": allModels})
|
||||
}
|
||||
|
||||
// sendActionToSimulator godoc
|
||||
// @Summary Send an action to simulator (only available if backend server is started with -amqp parameter)
|
||||
// @ID sendActionToSimulator
|
||||
// @Tags simulators
|
||||
// @Produce json
|
||||
// @Param inputAction query string true "Action for simulator"
|
||||
// @Success 200 {object} docs.ResponseError "Action sent successfully"
|
||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Param simulatorID path int true "Simulator ID"
|
||||
// @Router /simulators/{simulatorID}/action [post]
|
||||
func sendActionToSimulator(c *gin.Context) {
|
||||
|
||||
ok, s := checkPermissions(c, database.ModelSimulatorAction, database.Update, true)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var actions []amqp.Action
|
||||
err := c.BindJSON(&actions)
|
||||
if err != nil {
|
||||
helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
for _, action := range actions {
|
||||
if action.When == 0 {
|
||||
action.When = float32(now.Unix())
|
||||
}
|
||||
|
||||
err = amqp.SendActionAMQP(action, s.UUID)
|
||||
if err != nil {
|
||||
helper.InternalServerError(c, "Unable to send actions to simulator: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "OK.",
|
||||
})
|
||||
}
|
||||
|
|
|
@ -19,10 +19,7 @@ func (s *Simulator) save() error {
|
|||
func (s *Simulator) ByID(id uint) error {
|
||||
db := database.GetDB()
|
||||
err := db.Find(s, id).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("Simulator with id=%v does not exist", id)
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Simulator) update(updatedSimulator Simulator) error {
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func checkPermissions(c *gin.Context, modeltype database.ModelName, operation database.CRUD, hasID bool) (bool, Simulator) {
|
||||
func CheckPermissions(c *gin.Context, modeltype database.ModelName, operation database.CRUD, hasID bool) (bool, Simulator) {
|
||||
|
||||
var s Simulator
|
||||
|
||||
|
|
|
@ -51,6 +51,23 @@ func TestAddSimulatorAsAdmin(t *testing.T) {
|
|||
"/api/authenticate", "POST", helper.AdminCredentials)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// try to POST with non JSON body
|
||||
// should result in bad request
|
||||
code, resp, err := helper.TestEndpoint(router, token,
|
||||
"/api/simulators", "POST", "This is no JSON")
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// try to POST malformed simulator (required fields missing, validation should fail)
|
||||
// should result in an unprocessable entity
|
||||
newMalformedSimulator := SimulatorRequest{
|
||||
UUID: database.SimulatorB.UUID,
|
||||
}
|
||||
code, resp, err = helper.TestEndpoint(router, token,
|
||||
"/api/simulators", "POST", helper.KeyModels{"simulator": newMalformedSimulator})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// test POST simulators/ $newSimulator
|
||||
newSimulator := SimulatorRequest{
|
||||
UUID: database.SimulatorA.UUID,
|
||||
|
@ -59,7 +76,7 @@ func TestAddSimulatorAsAdmin(t *testing.T) {
|
|||
State: database.SimulatorA.State,
|
||||
Properties: database.SimulatorA.Properties,
|
||||
}
|
||||
code, resp, err := helper.TestEndpoint(router, token,
|
||||
code, resp, err = helper.TestEndpoint(router, token,
|
||||
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulator})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
@ -82,6 +99,13 @@ func TestAddSimulatorAsAdmin(t *testing.T) {
|
|||
// Compare GET's response with the newSimulator
|
||||
err = helper.CompareResponse(resp, helper.KeyModels{"simulator": newSimulator})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try to GET a simulator that does not exist
|
||||
// should result in not found
|
||||
code, resp, err = helper.TestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/simulators/%v", newSimulatorID+1), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||
}
|
||||
|
||||
func TestAddSimulatorAsUser(t *testing.T) {
|
||||
|
@ -142,6 +166,13 @@ func TestUpdateSimulatorAsAdmin(t *testing.T) {
|
|||
newSimulatorID, err := helper.GetResponseID(resp)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// try to PUT with non JSON body
|
||||
// should result in bad request
|
||||
code, resp, err = helper.TestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "PUT", "This is no JSON")
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Test PUT simulators
|
||||
newSimulator.Host = "ThisIsMyNewHost"
|
||||
code, resp, err = helper.TestEndpoint(router, token,
|
||||
|
@ -409,4 +440,11 @@ func TestGetSimulationModelsOfSimulator(t *testing.T) {
|
|||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
assert.Equal(t, 0, numberOfModels)
|
||||
|
||||
// Try to get models of simulator that does not exist
|
||||
// should result in not found
|
||||
code, resp, err = helper.TestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/simulators/%v/models", newSimulatorID+1), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ func (r *addSimulatorRequest) createSimulator() Simulator {
|
|||
return s
|
||||
}
|
||||
|
||||
func (r *updateSimulatorRequest) updatedSimulator(oldSimulator Simulator) (Simulator, error) {
|
||||
func (r *updateSimulatorRequest) updatedSimulator(oldSimulator Simulator) Simulator {
|
||||
// Use the old Simulator as a basis for the updated Simulator `s`
|
||||
s := oldSimulator
|
||||
|
||||
|
@ -89,5 +89,5 @@ func (r *updateSimulatorRequest) updatedSimulator(oldSimulator Simulator) (Simul
|
|||
s.Properties = r.Properties
|
||||
}
|
||||
|
||||
return s, nil
|
||||
return s
|
||||
}
|
||||
|
|
4
start.go
4
start.go
|
@ -64,6 +64,10 @@ func main() {
|
|||
file.RegisterFileEndpoints(api.Group("/files"))
|
||||
user.RegisterUserEndpoints(api.Group("/users"))
|
||||
simulator.RegisterSimulatorEndpoints(api.Group("/simulators"))
|
||||
// register simulator action endpoint only if AMQP client is used
|
||||
if database.WITH_AMQP == true {
|
||||
amqp.RegisterAMQPEndpoint(api.Group("/simulators"))
|
||||
}
|
||||
|
||||
r.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue