Merge branch 'renaming-simulator-simmodel' into 'master'

Renaming simulator and simmodel

See merge request acs/public/villas/web-backend-go!14
This commit is contained in:
Sonja Happ 2020-03-12 12:47:10 +01:00
commit 361121434b
37 changed files with 3484 additions and 3409 deletions

View file

@ -95,10 +95,10 @@ test:scenario:
variables: variables:
TEST_FOLDER: routes/scenario TEST_FOLDER: routes/scenario
test:simulationmodel: test:component-configuration:
extends: test:scenario extends: test:database
variables: variables:
TEST_FOLDER: routes/simulationmodel TEST_FOLDER: routes/component-configuration
test:signal: test:signal:
extends: test:database extends: test:database
@ -115,10 +115,10 @@ test:widget:
variables: variables:
TEST_FOLDER: routes/widget TEST_FOLDER: routes/widget
test:simulator: test:infrastructure-component:
extends: test:database extends: test:database
variables: variables:
TEST_FOLDER: routes/simulator TEST_FOLDER: routes/infrastructure-component
test:file: test:file:
extends: test:database extends: test:database

View file

@ -24,32 +24,32 @@ package amqp
import ( import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulator" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http" "net/http"
"time" "time"
) )
func RegisterAMQPEndpoint(r *gin.RouterGroup) { func RegisterAMQPEndpoint(r *gin.RouterGroup) {
r.POST("/:simulatorID/action", sendActionToSimulator) r.POST("/ICID/action", sendActionToIC)
} }
// sendActionToSimulator godoc // sendActionToIC godoc
// @Summary Send an action to simulator (only available if backend server is started with -amqp parameter) // @Summary Send an action to IC (only available if backend server is started with -amqp parameter)
// @ID sendActionToSimulator // @ID sendActionToIC
// @Tags AMQP // @Tags AMQP
// @Produce json // @Produce json
// @Param inputAction query string true "Action for simulator" // @Param inputAction query string true "Action for IC"
// @Success 200 {object} docs.ResponseError "Action sent successfully" // @Success 200 {object} docs.ResponseError "Action sent successfully"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param simulatorID path int true "Simulator ID" // @Param ICID path int true "InfrastructureComponent ID"
// @Router /simulators/{simulatorID}/action [post] // @Router /ic/{ICID}/action [post]
func sendActionToSimulator(c *gin.Context) { func sendActionToIC(c *gin.Context) {
ok, s := simulator.CheckPermissions(c, database.ModelSimulatorAction, database.Update, true) ok, s := infrastructure_component.CheckPermissions(c, database.ModelInfrastructureComponentAction, database.Update, true)
if !ok { if !ok {
return return
} }
@ -70,7 +70,7 @@ func sendActionToSimulator(c *gin.Context) {
err = SendActionAMQP(action, s.UUID) err = SendActionAMQP(action, s.UUID)
if err != nil { if err != nil {
helper.InternalServerError(c, "Unable to send actions to simulator: "+err.Error()) helper.InternalServerError(c, "Unable to send actions to IC: "+err.Error())
return return
} }
} }

View file

@ -77,8 +77,8 @@ func ConnectAMQP(uri string) error {
return fmt.Errorf("AMQP: failed to declare the exchange") return fmt.Errorf("AMQP: failed to declare the exchange")
} }
// add a queue for the simulators // add a queue for the ICs
simulatorQueue, err := client.channel.QueueDeclare("simulators", ICQueue, err := client.channel.QueueDeclare("infrastructure_components",
true, true,
false, false,
false, false,
@ -88,13 +88,13 @@ func ConnectAMQP(uri string) error {
return fmt.Errorf("AMQP: failed to declare the queue") return fmt.Errorf("AMQP: failed to declare the queue")
} }
err = client.channel.QueueBind(simulatorQueue.Name, "", VILLAS_EXCHANGE, false, nil) err = client.channel.QueueBind(ICQueue.Name, "", VILLAS_EXCHANGE, false, nil)
if err != nil { if err != nil {
return fmt.Errorf("AMQP: failed to bind the queue") return fmt.Errorf("AMQP: failed to bind the queue")
} }
// consume deliveries // consume deliveries
client.replies, err = client.channel.Consume(simulatorQueue.Name, client.replies, err = client.channel.Consume(ICQueue.Name,
"", "",
false, false,
false, false,
@ -120,15 +120,15 @@ func ConnectAMQP(uri string) error {
continue continue
} }
var sToBeUpdated database.Simulator var sToBeUpdated database.InfrastructureComponent
db := database.GetDB() db := database.GetDB()
simulatorUUID := gjson.Get(content, "properties.uuid").String() ICUUID := gjson.Get(content, "properties.uuid").String()
if simulatorUUID == "" { if ICUUID == "" {
log.Println("AMQP: Could not extract UUID of simulator from content of received message, SIMULATOR NOT UPDATED") log.Println("AMQP: Could not extract UUID of IC from content of received message, COMPONENT NOT UPDATED")
} else { } else {
err = db.Where("UUID = ?", simulatorUUID).Find(sToBeUpdated).Error err = db.Where("UUID = ?", ICUUID).Find(sToBeUpdated).Error
if err != nil { if err != nil {
log.Println("AMQP: Unable to find simulator with UUID: ", gjson.Get(content, "properties.uuid"), " DB error message: ", err) log.Println("AMQP: Unable to find IC with UUID: ", gjson.Get(content, "properties.uuid"), " DB error message: ", err)
} }
err = db.Model(&sToBeUpdated).Updates(map[string]interface{}{ err = db.Model(&sToBeUpdated).Updates(map[string]interface{}{
@ -140,10 +140,10 @@ func ConnectAMQP(uri string) error {
"RawProperties": gjson.Get(content, "properties"), "RawProperties": gjson.Get(content, "properties"),
}).Error }).Error
if err != nil { if err != nil {
log.Println("AMQP: Unable to update simulator in DB: ", err) log.Println("AMQP: Unable to update IC in DB: ", err)
} }
log.Println("AMQP: Updated simulator with UUID ", gjson.Get(content, "properties.uuid")) log.Println("AMQP: Updated IC with UUID ", gjson.Get(content, "properties.uuid"))
} }
} }
}() }()
@ -182,7 +182,7 @@ func SendActionAMQP(action Action, uuid string) error {
} }
func PingAMQP() error { func PingAMQP() error {
log.Println("AMQP: sending ping command to all simulators") log.Println("AMQP: sending ping command to all ICs")
var a Action var a Action
a.Act = "ping" a.Act = "ping"

View file

@ -55,9 +55,9 @@ read_users () {
-X GET | jq '.' && printf '\n' -X GET | jq '.' && printf '\n'
} }
read_simulators () { read_infrastructure_components () {
printf "> GET "$apiBase"/simulators\n" printf "> GET "$apiBase"/ic\n"
curl "$apiBase"/simulators -s \ curl "$apiBase"/ic -s \
-H "Contet-Type: application/json" \ -H "Contet-Type: application/json" \
-H "Authorization: Bearer $(< auth.jwt)" \ -H "Authorization: Bearer $(< auth.jwt)" \
-X GET | jq '.' && printf '\n' -X GET | jq '.' && printf '\n'
@ -114,7 +114,7 @@ login "$admin"
#create_user "$userC" #create_user "$userC"
#read_users #read_users
#read_user 1 #read_user 1
#read_simulators #read_infrastructure_components
create_user "$newUserW" create_user "$newUserW"
#read_users #read_users
read_user 4 read_user 4

View file

@ -102,9 +102,9 @@ func GetDB() *gorm.DB {
// TODO: Remove that function from the codebase and substitute the body // TODO: Remove that function from the codebase and substitute the body
// to the Dummy*() where it is called // to the Dummy*() where it is called
func DropTables(db *gorm.DB) { func DropTables(db *gorm.DB) {
db.DropTableIfExists(&Simulator{}) db.DropTableIfExists(&InfrastructureComponent{})
db.DropTableIfExists(&Signal{}) db.DropTableIfExists(&Signal{})
db.DropTableIfExists(&SimulationModel{}) db.DropTableIfExists(&ComponentConfiguration{})
db.DropTableIfExists(&File{}) db.DropTableIfExists(&File{})
db.DropTableIfExists(&Scenario{}) db.DropTableIfExists(&Scenario{})
db.DropTableIfExists(&User{}) db.DropTableIfExists(&User{})
@ -116,9 +116,9 @@ func DropTables(db *gorm.DB) {
// AutoMigrate the models // AutoMigrate the models
func MigrateModels(db *gorm.DB) { func MigrateModels(db *gorm.DB) {
db.AutoMigrate(&Simulator{}) db.AutoMigrate(&InfrastructureComponent{})
db.AutoMigrate(&Signal{}) db.AutoMigrate(&Signal{})
db.AutoMigrate(&SimulationModel{}) db.AutoMigrate(&ComponentConfiguration{})
db.AutoMigrate(&File{}) db.AutoMigrate(&File{})
db.AutoMigrate(&Scenario{}) db.AutoMigrate(&Scenario{})
db.AutoMigrate(&User{}) db.AutoMigrate(&User{})

View file

@ -107,8 +107,8 @@ func TestScenarioAssociations(t *testing.T) {
user0 := User0 user0 := User0
userA := UserA userA := UserA
userB := UserB userB := UserB
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
dashboardA := DashboardA dashboardA := DashboardA
dashboardB := DashboardB dashboardB := DashboardB
@ -121,9 +121,9 @@ func TestScenarioAssociations(t *testing.T) {
assert.NoError(t, db.Create(&userA).Error) // Normal User assert.NoError(t, db.Create(&userA).Error) // Normal User
assert.NoError(t, db.Create(&userB).Error) // Normal User assert.NoError(t, db.Create(&userB).Error) // Normal User
// add simulation models to DB // add component configurations to DB
assert.NoError(t, db.Create(&modelA).Error) assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&modelB).Error) assert.NoError(t, db.Create(&configB).Error)
// add dashboards to DB // add dashboards to DB
assert.NoError(t, db.Create(&dashboardA).Error) assert.NoError(t, db.Create(&dashboardA).Error)
@ -136,9 +136,9 @@ func TestScenarioAssociations(t *testing.T) {
assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userA).Error) assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userA).Error)
assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userB).Error) assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userB).Error)
// add scenario has many simulation models associations // add scenario has many component configurations associations
assert.NoError(t, db.Model(&scenarioA).Association("SimulationModels").Append(&modelA).Error) assert.NoError(t, db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&scenarioA).Association("SimulationModels").Append(&modelB).Error) assert.NoError(t, db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configB).Error)
// Scenario HM Dashboards // Scenario HM Dashboards
assert.NoError(t, db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error) assert.NoError(t, db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error)
@ -156,12 +156,12 @@ func TestScenarioAssociations(t *testing.T) {
"Expected to have %v Users. Has %v.", 2, len(users)) "Expected to have %v Users. Has %v.", 2, len(users))
} }
// Get simulation models of scenario1 // Get component configurations of scenario1
var models []SimulationModel var configs []ComponentConfiguration
assert.NoError(t, db.Model(&scenario1).Related(&models, "SimulationModels").Error) assert.NoError(t, db.Model(&scenario1).Related(&configs, "ComponentConfigurations").Error)
if len(models) != 2 { if len(configs) != 2 {
assert.Fail(t, "Scenario Associations", assert.Fail(t, "Scenario Associations",
"Expected to have %v simulation models. Has %v.", 2, len(models)) "Expected to have %v component configs. Has %v.", 2, len(configs))
} }
// Get dashboards of scenario1 // Get dashboards of scenario1
@ -173,50 +173,50 @@ func TestScenarioAssociations(t *testing.T) {
} }
} }
func TestSimulatorAssociations(t *testing.T) { func TestICAssociations(t *testing.T) {
DropTables(db) DropTables(db)
MigrateModels(db) MigrateModels(db)
// create copies of global test data // create copies of global test data
simulatorA := SimulatorA icA := ICA
simulatorB := SimulatorB icB := ICB
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
// add simulators to DB // add ICs to DB
assert.NoError(t, db.Create(&simulatorA).Error) assert.NoError(t, db.Create(&icA).Error)
assert.NoError(t, db.Create(&simulatorB).Error) assert.NoError(t, db.Create(&icB).Error)
// add simulation models to DB // add component configurations to DB
assert.NoError(t, db.Create(&modelA).Error) assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&modelB).Error) assert.NoError(t, db.Create(&configB).Error)
// add simulator has many simulation models association to DB // add IC has many component configurations association to DB
assert.NoError(t, db.Model(&simulatorA).Association("SimulationModels").Append(&modelA).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&simulatorA).Association("SimulationModels").Append(&modelB).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
var simulator1 Simulator var ic1 InfrastructureComponent
assert.NoError(t, db.Find(&simulator1, 1).Error, fmt.Sprintf("Find Simulator with ID=1")) assert.NoError(t, db.Find(&ic1, 1).Error, fmt.Sprintf("Find InfrastructureComponent with ID=1"))
assert.EqualValues(t, "Host_A", simulator1.Host) assert.EqualValues(t, "Host_A", ic1.Host)
// Get simulation models of simulator1 // Get Component Configurations of ic1
var models []SimulationModel var configs []ComponentConfiguration
assert.NoError(t, db.Model(&simulator1).Association("SimulationModels").Find(&models).Error) assert.NoError(t, db.Model(&ic1).Association("ComponentConfigurations").Find(&configs).Error)
if len(models) != 2 { if len(configs) != 2 {
assert.Fail(t, "Simulator Associations", assert.Fail(t, "InfrastructureComponent Associations",
"Expected to have %v SimulationModels. Has %v.", 2, len(models)) "Expected to have %v Component Configurations. Has %v.", 2, len(configs))
} }
} }
func TestSimulationModelAssociations(t *testing.T) { func TestComponentConfigurationAssociations(t *testing.T) {
DropTables(db) DropTables(db)
MigrateModels(db) MigrateModels(db)
// create copies of global test data // create copies of global test data
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
outSignalA := OutSignalA outSignalA := OutSignalA
outSignalB := OutSignalB outSignalB := OutSignalB
inSignalA := InSignalA inSignalA := InSignalA
@ -225,12 +225,12 @@ func TestSimulationModelAssociations(t *testing.T) {
fileB := FileB fileB := FileB
fileC := FileC fileC := FileC
fileD := FileD fileD := FileD
simulatorA := SimulatorA icA := ICA
simulatorB := SimulatorB icB := ICB
// add simulation models to DB // add Component Configurations to DB
assert.NoError(t, db.Create(&modelA).Error) assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&modelB).Error) assert.NoError(t, db.Create(&configB).Error)
// add signals to DB // add signals to DB
assert.NoError(t, db.Create(&outSignalA).Error) assert.NoError(t, db.Create(&outSignalA).Error)
@ -244,46 +244,46 @@ func TestSimulationModelAssociations(t *testing.T) {
assert.NoError(t, db.Create(&fileC).Error) assert.NoError(t, db.Create(&fileC).Error)
assert.NoError(t, db.Create(&fileD).Error) assert.NoError(t, db.Create(&fileD).Error)
// add simulators to DB // add ICs to DB
assert.NoError(t, db.Create(&simulatorA).Error) assert.NoError(t, db.Create(&icA).Error)
assert.NoError(t, db.Create(&simulatorB).Error) assert.NoError(t, db.Create(&icB).Error)
// add simulation model has many signals associations // add Component Configuration has many signals associations
assert.NoError(t, db.Model(&modelA).Association("InputMapping").Append(&inSignalA).Error) assert.NoError(t, db.Model(&configA).Association("InputMapping").Append(&inSignalA).Error)
assert.NoError(t, db.Model(&modelA).Association("InputMapping").Append(&inSignalB).Error) assert.NoError(t, db.Model(&configA).Association("InputMapping").Append(&inSignalB).Error)
assert.NoError(t, db.Model(&modelA).Association("OutputMapping").Append(&outSignalA).Error) assert.NoError(t, db.Model(&configA).Association("OutputMapping").Append(&outSignalA).Error)
assert.NoError(t, db.Model(&modelA).Association("OutputMapping").Append(&outSignalB).Error) assert.NoError(t, db.Model(&configA).Association("OutputMapping").Append(&outSignalB).Error)
// add simulation model has many files associations // add Component Configuration has many files associations
assert.NoError(t, db.Model(&modelA).Association("Files").Append(&fileC).Error) assert.NoError(t, db.Model(&configA).Association("Files").Append(&fileC).Error)
assert.NoError(t, db.Model(&modelA).Association("Files").Append(&fileD).Error) assert.NoError(t, db.Model(&configA).Association("Files").Append(&fileD).Error)
// associate simulation models with simulators // associate Component Configurations with IC
assert.NoError(t, db.Model(&simulatorA).Association("SimulationModels").Append(&modelA).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&simulatorA).Association("SimulationModels").Append(&modelB).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
var model1 SimulationModel var config1 ComponentConfiguration
assert.NoError(t, db.Find(&model1, 1).Error, fmt.Sprintf("Find SimulationModel with ID=1")) assert.NoError(t, db.Find(&config1, 1).Error, fmt.Sprintf("Find ComponentConfiguration with ID=1"))
assert.EqualValues(t, "SimulationModel_A", model1.Name) assert.EqualValues(t, ConfigA.Name, config1.Name)
// Check simulator ID // Check IC ID
if model1.SimulatorID != 1 { if config1.ICID != 1 {
assert.Fail(t, "Simulation Model expected to have Simulator ID 1, but is %v", model1.SimulatorID) assert.Fail(t, "Component Configurations expected to have Infrastructure Component ID 1, but is %v", config1.ICID)
} }
// Get OutputMapping signals of model1 // Get OutputMapping signals of config1
var signals []Signal var signals []Signal
assert.NoError(t, db.Model(&model1).Where("Direction = ?", "out").Related(&signals, "OutputMapping").Error) assert.NoError(t, db.Model(&config1).Where("Direction = ?", "out").Related(&signals, "OutputMapping").Error)
if len(signals) != 2 { if len(signals) != 2 {
assert.Fail(t, "SimulationModel Associations", assert.Fail(t, "ComponentConfiguration Associations",
"Expected to have %v Output Signals. Has %v.", 2, len(signals)) "Expected to have %v Output Signals. Has %v.", 2, len(signals))
} }
// Get files of model1 // Get files of config1
var files []File var files []File
assert.NoError(t, db.Model(&model1).Related(&files, "Files").Error) assert.NoError(t, db.Model(&config1).Related(&files, "Files").Error)
if len(files) != 2 { if len(files) != 2 {
assert.Fail(t, "SimulationModel Associations", assert.Fail(t, "ComponentConfiguration Associations",
"Expected to have %v Files. Has %v.", 2, len(files)) "Expected to have %v Files. Has %v.", 2, len(files))
} }
} }

View file

@ -65,35 +65,35 @@ type Scenario struct {
StartParameters postgres.Jsonb `json:"startParameters"` StartParameters postgres.Jsonb `json:"startParameters"`
// Users that have access to the scenario // Users that have access to the scenario
Users []*User `json:"-" gorm:"many2many:user_scenarios;"` Users []*User `json:"-" gorm:"many2many:user_scenarios;"`
// SimulationModels that belong to the scenario // ComponentConfigurations that belong to the scenario
SimulationModels []SimulationModel `json:"-" gorm:"foreignkey:ScenarioID" ` ComponentConfigurations []ComponentConfiguration `json:"-" gorm:"foreignkey:ScenarioID" `
// Dashboards that belong to the Scenario // Dashboards that belong to the Scenario
Dashboards []Dashboard `json:"-" gorm:"foreignkey:ScenarioID" ` Dashboards []Dashboard `json:"-" gorm:"foreignkey:ScenarioID" `
} }
// SimulationModel data model // ComponentConfiguration data model
type SimulationModel struct { type ComponentConfiguration struct {
Model Model
// Name of simulation model // Name of Component Configuration
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:0"` OutputLength int `json:"outputLength" gorm:"default:0"`
// Number of input signals // Number of input signals
InputLength int `json:"inputLength" gorm:"default:0"` InputLength int `json:"inputLength" gorm:"default:0"`
// Start parameters of simulation model as JSON // Start parameters of Component Configuration 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 Component Configuration belongs
ScenarioID uint `json:"scenarioID"` ScenarioID uint `json:"scenarioID"`
// ID of simulator associated with simulation model // ID of IC associated with Component Configuration
SimulatorID uint `json:"simulatorID"` ICID uint `json:"icID"`
// Mapping of output signals of the simulation model, order of signals is important // Mapping of output signals of the ComponentConfiguration, order of signals is important
OutputMapping []Signal `json:"-" gorm:"foreignkey:SimulationModelID"` OutputMapping []Signal `json:"-" gorm:"foreignkey:ConfigID"`
// Mapping of input signals of the simulation model, order of signals is important // Mapping of input signals of the Component Configuration, order of signals is important
InputMapping []Signal `json:"-" gorm:"foreignkey:SimulationModelID"` InputMapping []Signal `json:"-" gorm:"foreignkey:ConfigID"`
// Files of simulation model (can be CIM and other simulation model file formats) // Files of Component Configuration (can be CIM and other ComponentConfiguration file formats)
Files []File `json:"-" gorm:"foreignkey:SimulationModelID"` Files []File `json:"-" gorm:"foreignkey:ConfigID"`
// Currently selected simulation model FileID // Currently selected FileID
SelectedModelFileID uint `json:"selectedModelFileID" gorm:"default:0"` SelectedFileID uint `json:"selectedFileID" gorm:"default:0"`
} }
// Signal data model // Signal data model
@ -107,31 +107,31 @@ type Signal struct {
Index uint `json:"index"` Index uint `json:"index"`
// Direction of the signal (in or out) // Direction of the signal (in or out)
Direction string `json:"direction"` Direction string `json:"direction"`
// ID of simulation model // ID of Component Configuration
SimulationModelID uint `json:"simulationModelID"` ConfigID uint `json:"configID"`
} }
// Simulator data model // InfrastructureComponent data model
type Simulator struct { type InfrastructureComponent struct {
Model Model
// UUID of the simulator // UUID of the IC
UUID string `json:"uuid" gorm:"not null"` UUID string `json:"uuid" gorm:"not null"`
// Host if the simulator // Host if the IC
Host string `json:"host" gorm:"default:''"` Host string `json:"host" gorm:"default:''"`
// Model type supported by the simulator // Model type supported by the IC
Modeltype string `json:"modelType" gorm:"default:''"` Modeltype string `json:"modelType" gorm:"default:''"`
// Uptime of the simulator // Uptime of the IC
Uptime int `json:"uptime" gorm:"default:0"` Uptime int `json:"uptime" gorm:"default:0"`
// State of the simulator // State of the IC
State string `json:"state" gorm:"default:''"` State string `json:"state" gorm:"default:''"`
// Time of last state update // Time of last state update
StateUpdateAt string `json:"stateUpdateAt" gorm:"default:''"` StateUpdateAt string `json:"stateUpdateAt" gorm:"default:''"`
// Properties of simulator as JSON string // Properties of IC as JSON string
Properties postgres.Jsonb `json:"properties"` Properties postgres.Jsonb `json:"properties"`
// Raw properties of simulator as JSON string // Raw properties of IC as JSON string
RawProperties postgres.Jsonb `json:"rawProperties"` RawProperties postgres.Jsonb `json:"rawProperties"`
// SimulationModels in which the simulator is used // ComponentConfigurations in which the IC is used
SimulationModels []SimulationModel `json:"-" gorm:"foreignkey:SimulatorID"` ComponentConfigurations []ComponentConfiguration `json:"-" gorm:"foreignkey:ICID"`
} }
// Dashboard data model // Dashboard data model
@ -195,8 +195,8 @@ type File struct {
ImageWidth uint `json:"imageWidth"` ImageWidth uint `json:"imageWidth"`
// Last modification time of file // Last modification time of file
Date string `json:"date"` Date string `json:"date"`
// ID of model to which file belongs // ID of Component Configuration to which file belongs
SimulationModelID uint `json:"simulationModelID"` ConfigID uint `json:"configID"`
// ID of widget to which file belongs // ID of widget to which file belongs
WidgetID uint `json:"widgetID"` WidgetID uint `json:"widgetID"`
// File itself // File itself

View file

@ -38,11 +38,11 @@ type ModelName string
const ModelUser = ModelName("user") const ModelUser = ModelName("user")
const ModelUsers = ModelName("users") const ModelUsers = ModelName("users")
const ModelScenario = ModelName("scenario") const ModelScenario = ModelName("scenario")
const ModelSimulator = ModelName("simulator") const ModelInfrastructureComponent = ModelName("ic")
const ModelSimulatorAction = ModelName("simulatoraction") const ModelInfrastructureComponentAction = ModelName("icaction")
const ModelDashboard = ModelName("dashboard") const ModelDashboard = ModelName("dashboard")
const ModelWidget = ModelName("widget") const ModelWidget = ModelName("widget")
const ModelSimulationModel = ModelName("simulationmodel") const ModelComponentConfiguration = ModelName("component-configuration")
const ModelSignal = ModelName("signal") const ModelSignal = ModelName("signal")
const ModelFile = ModelName("file") const ModelFile = ModelName("file")
@ -76,9 +76,9 @@ var Roles = RoleActions{
ModelUser: crud, ModelUser: crud,
ModelUsers: crud, ModelUsers: crud,
ModelScenario: crud, ModelScenario: crud,
ModelSimulationModel: crud, ModelComponentConfiguration: crud,
ModelSimulator: crud, ModelInfrastructureComponent: crud,
ModelSimulatorAction: crud, ModelInfrastructureComponentAction: crud,
ModelWidget: crud, ModelWidget: crud,
ModelDashboard: crud, ModelDashboard: crud,
ModelSignal: crud, ModelSignal: crud,
@ -88,9 +88,9 @@ var Roles = RoleActions{
ModelUser: _ru_, ModelUser: _ru_,
ModelUsers: none, ModelUsers: none,
ModelScenario: crud, ModelScenario: crud,
ModelSimulationModel: crud, ModelComponentConfiguration: crud,
ModelSimulator: _r__, ModelInfrastructureComponent: _r__,
ModelSimulatorAction: _ru_, ModelInfrastructureComponentAction: _ru_,
ModelWidget: crud, ModelWidget: crud,
ModelDashboard: crud, ModelDashboard: crud,
ModelSignal: crud, ModelSignal: crud,
@ -98,11 +98,11 @@ var Roles = RoleActions{
}, },
"Guest": { "Guest": {
ModelScenario: _r__, ModelScenario: _r__,
ModelSimulationModel: _r__, ModelComponentConfiguration: _r__,
ModelDashboard: _r__, ModelDashboard: _r__,
ModelWidget: _r__, ModelWidget: _r__,
ModelSimulator: _r__, ModelInfrastructureComponent: _r__,
ModelSimulatorAction: _r__, ModelInfrastructureComponentAction: _r__,
ModelUser: _ru_, ModelUser: _ru_,
ModelUsers: none, ModelUsers: none,
ModelSignal: _r__, ModelSignal: _r__,

View file

@ -55,12 +55,12 @@ var UserB = User{Username: "User_B", Password: string(pwB),
var UserC = User{Username: "User_C", Password: string(pwC), var UserC = User{Username: "User_C", Password: string(pwC),
Role: "Guest", Mail: "User_C@example.com", Active: true} Role: "Guest", Mail: "User_C@example.com", Active: true}
// Simulators // Infrastructure components
var propertiesA = json.RawMessage(`{"name" : "TestNameA", "category" : "CategoryA", "location" : "anywhere on earth", "type": "dummy"}`) var propertiesA = json.RawMessage(`{"name" : "DPsim simulator", "category" : "Simulator", "location" : "ACSlab", "type": "DPsim"}`)
var propertiesB = json.RawMessage(`{"name" : "TestNameB", "category" : "CategoryB", "location" : "where ever you want", "type": "generic"}`) var propertiesB = json.RawMessage(`{"name" : "VILLASnode gateway", "category" : "Gateway", "location" : "ACSlab", "type": "VILLASnode"}`)
var SimulatorA = Simulator{ var ICA = InfrastructureComponent{
UUID: "4854af30-325f-44a5-ad59-b67b2597de68", UUID: "4854af30-325f-44a5-ad59-b67b2597de68",
Host: "Host_A", Host: "Host_A",
Modeltype: "ModelTypeA", Modeltype: "ModelTypeA",
@ -71,7 +71,7 @@ var SimulatorA = Simulator{
RawProperties: postgres.Jsonb{propertiesA}, RawProperties: postgres.Jsonb{propertiesA},
} }
var SimulatorB = Simulator{ var ICB = InfrastructureComponent{
UUID: "7be0322d-354e-431e-84bd-ae4c9633138b", UUID: "7be0322d-354e-431e-84bd-ae4c9633138b",
Host: "Host_B", Host: "Host_B",
Modeltype: "ModelTypeB", Modeltype: "ModelTypeB",
@ -98,18 +98,18 @@ var ScenarioB = Scenario{
StartParameters: postgres.Jsonb{startParametersB}, StartParameters: postgres.Jsonb{startParametersB},
} }
// Simulation Models // Component Configuration
var SimulationModelA = SimulationModel{ var ConfigA = ComponentConfiguration{
Name: "SimulationModel_A", Name: "Example simulation",
StartParameters: postgres.Jsonb{startParametersA}, StartParameters: postgres.Jsonb{startParametersA},
SelectedModelFileID: 3, SelectedFileID: 3,
} }
var SimulationModelB = SimulationModel{ var ConfigB = ComponentConfiguration{
Name: "SimulationModel_B", Name: "VILLASnode gateway X",
StartParameters: postgres.Jsonb{startParametersB}, StartParameters: postgres.Jsonb{startParametersB},
SelectedModelFileID: 4, SelectedFileID: 4,
} }
// Signals // Signals
@ -198,7 +198,7 @@ var customPropertiesLabel = json.RawMessage(`{"textSize" : "20", "fontColor" : 5
var customPropertiesButton = json.RawMessage(`{"toggle" : "Value1", "on_value" : "Value2", "off_value" : Value3}`) var customPropertiesButton = json.RawMessage(`{"toggle" : "Value1", "on_value" : "Value2", "off_value" : Value3}`)
var customPropertiesCustomActions = json.RawMessage(`{"actions" : "Value1", "icon" : "Value2"}`) var customPropertiesCustomActions = json.RawMessage(`{"actions" : "Value1", "icon" : "Value2"}`)
var customPropertiesGauge = json.RawMessage(`{ "valueMin": 0, "valueMax": 1}`) var customPropertiesGauge = json.RawMessage(`{ "valueMin": 0, "valueMax": 1}`)
var customPropertiesLamp = json.RawMessage(`{"simulationModel" : "null", "signal" : 0, "on_color" : 4, "off_color": 2 , "threshold" : 0.5}`) var customPropertiesLamp = json.RawMessage(`{"signal" : 0, "on_color" : 4, "off_color": 2 , "threshold" : 0.5}`)
var WidgetA = Widget{ var WidgetA = Widget{
Name: "Label", Name: "Label",
@ -316,8 +316,8 @@ func DBAddTestData(db *gorm.DB) error {
userB := UserB userB := UserB
userC := UserC userC := UserC
simulatorA := SimulatorA ICA := ICA
simulatorB := SimulatorB ICB := ICB
scenarioA := ScenarioA scenarioA := ScenarioA
scenarioB := ScenarioB scenarioB := ScenarioB
@ -327,8 +327,8 @@ func DBAddTestData(db *gorm.DB) error {
inSignalA := InSignalA inSignalA := InSignalA
inSignalB := InSignalB inSignalB := InSignalB
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
dashboardA := DashboardA dashboardA := DashboardA
dashboardB := DashboardB dashboardB := DashboardB
@ -354,9 +354,9 @@ func DBAddTestData(db *gorm.DB) error {
// add Guest user to DB // add Guest user to DB
err = db.Create(&userC).Error err = db.Create(&userC).Error
// Simulators // ICs
err = db.Create(&simulatorA).Error err = db.Create(&ICA).Error
err = db.Create(&simulatorB).Error err = db.Create(&ICB).Error
// Scenarios // Scenarios
err = db.Create(&scenarioA).Error err = db.Create(&scenarioA).Error
@ -368,9 +368,9 @@ func DBAddTestData(db *gorm.DB) error {
err = db.Create(&outSignalA).Error err = db.Create(&outSignalA).Error
err = db.Create(&outSignalB).Error err = db.Create(&outSignalB).Error
// Simulation Models // Component Configuration
err = db.Create(&modelA).Error err = db.Create(&configA).Error
err = db.Create(&modelB).Error err = db.Create(&configB).Error
// Dashboards // Dashboards
err = db.Create(&dashboardA).Error err = db.Create(&dashboardA).Error
@ -400,9 +400,9 @@ func DBAddTestData(db *gorm.DB) error {
err = db.Model(&scenarioA).Association("Users").Append(&userC).Error err = db.Model(&scenarioA).Association("Users").Append(&userC).Error
err = db.Model(&scenarioA).Association("Users").Append(&user0).Error err = db.Model(&scenarioA).Association("Users").Append(&user0).Error
// Scenario HM SimulationModels // Scenario HM Component Configurations
err = db.Model(&scenarioA).Association("SimulationModels").Append(&modelA).Error err = db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configA).Error
err = db.Model(&scenarioA).Association("SimulationModels").Append(&modelB).Error err = db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configB).Error
// Scenario HM Dashboards // Scenario HM Dashboards
err = db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error err = db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error
@ -415,19 +415,19 @@ func DBAddTestData(db *gorm.DB) error {
err = db.Model(&dashboardA).Association("Widgets").Append(&widgetD).Error err = db.Model(&dashboardA).Association("Widgets").Append(&widgetD).Error
err = db.Model(&dashboardA).Association("Widgets").Append(&widgetE).Error err = db.Model(&dashboardA).Association("Widgets").Append(&widgetE).Error
// SimulationModel HM Signals // ComponentConfiguration HM Signals
err = db.Model(&modelA).Association("InputMapping").Append(&inSignalA).Error err = db.Model(&configA).Association("InputMapping").Append(&inSignalA).Error
err = db.Model(&modelA).Association("InputMapping").Append(&inSignalB).Error err = db.Model(&configA).Association("InputMapping").Append(&inSignalB).Error
err = db.Model(&modelA).Association("InputMapping").Append(&outSignalA).Error err = db.Model(&configA).Association("InputMapping").Append(&outSignalA).Error
err = db.Model(&modelA).Association("InputMapping").Append(&outSignalB).Error err = db.Model(&configA).Association("InputMapping").Append(&outSignalB).Error
// SimulationModel HM Files // ComponentConfiguration HM Files
err = db.Model(&modelA).Association("Files").Append(&fileC).Error err = db.Model(&configA).Association("Files").Append(&fileC).Error
err = db.Model(&modelA).Association("Files").Append(&fileD).Error err = db.Model(&configA).Association("Files").Append(&fileD).Error
// Simulator HM SimulationModels // InfrastructureComponent HM ComponentConfigurations
err = db.Model(&simulatorA).Association("SimulationModels").Append(&modelA).Error err = db.Model(&ICA).Association("ComponentConfigurations").Append(&configA).Error
err = db.Model(&simulatorA).Association("SimulationModels").Append(&modelB).Error err = db.Model(&ICA).Association("ComponentConfigurations").Append(&configB).Error
// Widget HM Files // Widget HM Files
err = db.Model(&widgetA).Association("Files").Append(&fileA).Error err = db.Model(&widgetA).Association("Files").Append(&fileA).Error

File diff suppressed because it is too large Load diff

View file

@ -46,12 +46,12 @@ type ResponseUser struct {
user database.User user database.User
} }
type ResponseSimulators struct { type ResponseICs struct {
simulators []database.Simulator ics []database.InfrastructureComponent
} }
type ResponseSimulator struct { type ResponseIC struct {
simulator database.Simulator ic database.InfrastructureComponent
} }
type ResponseScenarios struct { type ResponseScenarios struct {
@ -62,12 +62,12 @@ type ResponseScenario struct {
scenario database.Scenario scenario database.Scenario
} }
type ResponseSimulationModels struct { type ResponseConfigs struct {
simulationModels []database.SimulationModel configs []database.ComponentConfiguration
} }
type ResponseSimulationModel struct { type ResponseConfig struct {
simulationModel database.SimulationModel config database.ComponentConfiguration
} }
type ResponseDashboards struct { type ResponseDashboards struct {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, endpoints. /** component_configuration package, endpoints.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
@ -31,27 +31,27 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
) )
func RegisterSimulationModelEndpoints(r *gin.RouterGroup) { func RegisterComponentConfigurationEndpoints(r *gin.RouterGroup) {
r.GET("", getSimulationModels) r.GET("", getConfigs)
r.POST("", addSimulationModel) r.POST("", addConfig)
r.PUT("/:modelID", updateSimulationModel) r.PUT("/:configID", updateConfig)
r.GET("/:modelID", getSimulationModel) r.GET("/:configID", getConfig)
r.DELETE("/:modelID", deleteSimulationModel) r.DELETE("/:configID", deleteConfig)
} }
// getSimulationModels godoc // getConfigs godoc
// @Summary Get all simulation models of scenario // @Summary Get all component configurations of scenario
// @ID getSimulationModels // @ID getConfigs
// @Produce json // @Produce json
// @Tags simulationModels // @Tags component-configurations
// @Success 200 {object} docs.ResponseSimulationModels "Simulation models which belong to scenario" // @Success 200 {object} docs.ResponseConfigs "Component configurations which belong to scenario"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param scenarioID query int true "Scenario ID" // @Param scenarioID query int true "Scenario ID"
// @Router /models [get] // @Router /configs [get]
func getSimulationModels(c *gin.Context) { func getConfigs(c *gin.Context) {
ok, so := scenario.CheckPermissions(c, database.Read, "query", -1) ok, so := scenario.CheckPermissions(c, database.Read, "query", -1)
if !ok { if !ok {
@ -59,32 +59,32 @@ func getSimulationModels(c *gin.Context) {
} }
db := database.GetDB() db := database.GetDB()
var models []database.SimulationModel var configs []database.ComponentConfiguration
err := db.Order("ID asc").Model(so).Related(&models, "Models").Error err := db.Order("ID asc").Model(so).Related(&configs, "ComponentConfigurations").Error
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModels": models}) c.JSON(http.StatusOK, gin.H{"configs": configs})
} }
} }
// addSimulationModel godoc // addConfig godoc
// @Summary Add a simulation model to a scenario // @Summary Add a component configuration to a scenario
// @ID addSimulationModel // @ID addConfig
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Tags simulationModels // @Tags component-configurations
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was added" // @Success 200 {object} docs.ResponseConfig "Component configuration that was added"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSimulationModel body simulationmodel.addSimulationModelRequest true "Simulation model to be added incl. IDs of scenario and simulator" // @Param inputConfig body component_configuration.addConfigRequest true "component configuration to be added incl. IDs of scenario and IC"
// @Router /models [post] // @Router /configs [post]
func addSimulationModel(c *gin.Context) { func addConfig(c *gin.Context) {
// Bind the request to JSON // Bind the request to JSON
var req addSimulationModelRequest var req addConfigRequest
err := c.ShouldBindJSON(&req) err := c.ShouldBindJSON(&req)
if err != nil { if err != nil {
helper.BadRequestError(c, "Bad request. Error binding form data to JSON: "+err.Error()) helper.BadRequestError(c, "Bad request. Error binding form data to JSON: "+err.Error())
@ -97,46 +97,46 @@ func addSimulationModel(c *gin.Context) {
return return
} }
// Create the new simulation model from the request // Create the new Component Configuration from the request
newSimulationModel := req.createSimulationModel() newConfig := req.createConfig()
// check access to the scenario // check access to the scenario
ok, _ := scenario.CheckPermissions(c, database.Update, "body", int(newSimulationModel.ScenarioID)) ok, _ := scenario.CheckPermissions(c, database.Update, "body", int(newConfig.ScenarioID))
if !ok { if !ok {
return return
} }
// add the new simulation model to the scenario // add the new Component Configuration to the scenario
err = newSimulationModel.addToScenario() err = newConfig.addToScenario()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModel": newSimulationModel.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": newConfig.ComponentConfiguration})
} }
} }
// updateSimulationModel godoc // updateConfig godoc
// @Summary Update a simulation model // @Summary Update a component configuration
// @ID updateSimulationModel // @ID updateConfig
// @Tags simulationModels // @Tags component-configurations
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was added" // @Success 200 {object} docs.ResponseConfig "Component configuration that was added"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSimulationModel body simulationmodel.updateSimulationModelRequest true "Simulation model to be updated" // @Param inputConfig body component_configuration.updateConfigRequest true "component configuration to be updated"
// @Param modelID path int true "Model ID" // @Param configID path int true "Config ID"
// @Router /models/{modelID} [put] // @Router /configs/{configID} [put]
func updateSimulationModel(c *gin.Context) { func updateConfig(c *gin.Context) {
ok, oldSimulationModel := CheckPermissions(c, database.Update, "path", -1) ok, oldConfig := CheckPermissions(c, database.Update, "path", -1)
if !ok { if !ok {
return return
} }
var req updateSimulationModelRequest var req updateConfigRequest
err := c.BindJSON(&req) err := c.BindJSON(&req)
if err != nil { if err != nil {
helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error())
@ -144,59 +144,59 @@ func updateSimulationModel(c *gin.Context) {
} }
// Validate the request // Validate the request
if err := req.SimulationModel.validate(); err != nil { if err := req.Config.validate(); err != nil {
helper.BadRequestError(c, err.Error()) helper.BadRequestError(c, err.Error())
return return
} }
// Create the updatedSimulationModel from oldSimulationModel // Create the updateConfig from oldConfig
updatedSimulationModel := req.updatedSimulationModel(oldSimulationModel) updatedConfig := req.updateConfig(oldConfig)
// Finally, update the simulation model // Finally, update the Component Configuration
err = oldSimulationModel.Update(updatedSimulationModel) err = oldConfig.Update(updatedConfig)
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModel": updatedSimulationModel.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": updatedConfig.ComponentConfiguration})
} }
} }
// getSimulationModel godoc // getConfig godoc
// @Summary Get a simulation model // @Summary Get a component configuration
// @ID getSimulationModel // @ID getConfig
// @Tags simulationModels // @Tags component-configurations
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was requested" // @Success 200 {object} docs.ResponseConfig "component configuration that was requested"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param modelID path int true "Model ID" // @Param configID path int true "Config ID"
// @Router /models/{modelID} [get] // @Router /configs/{configID} [get]
func getSimulationModel(c *gin.Context) { func getConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Read, "path", -1) ok, m := CheckPermissions(c, database.Read, "path", -1)
if !ok { if !ok {
return return
} }
c.JSON(http.StatusOK, gin.H{"simulationModel": m.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": m.ComponentConfiguration})
} }
// deleteSimulationModel godoc // deleteConfig godoc
// @Summary Delete a simulation model // @Summary Delete a component configuration
// @ID deleteSimulationModel // @ID deleteConfig
// @Tags simulationModels // @Tags component-configurations
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was deleted" // @Success 200 {object} docs.ResponseConfig "component configuration that was deleted"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param modelID path int true "Model ID" // @Param configID path int true "Config ID"
// @Router /models/{modelID} [delete] // @Router /configs/{configID} [delete]
func deleteSimulationModel(c *gin.Context) { func deleteConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Delete, "path", -1) ok, m := CheckPermissions(c, database.Delete, "path", -1)
if !ok { if !ok {
@ -205,6 +205,6 @@ func deleteSimulationModel(c *gin.Context) {
err := m.delete() err := m.delete()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModel": m.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": m.ComponentConfiguration})
} }
} }

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, methods. /** component_configuration package, methods.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,25 +19,25 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulator"
) )
type SimulationModel struct { type ComponentConfiguration struct {
database.SimulationModel database.ComponentConfiguration
} }
func (m *SimulationModel) save() error { func (m *ComponentConfiguration) save() error {
db := database.GetDB() db := database.GetDB()
err := db.Create(m).Error err := db.Create(m).Error
return err return err
} }
func (m *SimulationModel) ByID(id uint) error { func (m *ComponentConfiguration) ByID(id uint) error {
db := database.GetDB() db := database.GetDB()
err := db.Find(m, id).Error err := db.Find(m, id).Error
if err != nil { if err != nil {
@ -46,7 +46,7 @@ func (m *SimulationModel) ByID(id uint) error {
return nil return nil
} }
func (m *SimulationModel) addToScenario() error { func (m *ComponentConfiguration) addToScenario() error {
db := database.GetDB() db := database.GetDB()
var so scenario.Scenario var so scenario.Scenario
err := so.ByID(m.ScenarioID) err := so.ByID(m.ScenarioID)
@ -54,65 +54,65 @@ func (m *SimulationModel) addToScenario() error {
return err return err
} }
// save simulation model to DB // save component configuration to DB
err = m.save() err = m.save()
if err != nil { if err != nil {
return err return err
} }
// associate simulator with simulation model // associate IC with component configuration
var simltr simulator.Simulator var ic infrastructure_component.InfrastructureComponent
err = simltr.ByID(m.SimulatorID) err = ic.ByID(m.ICID)
err = db.Model(&simltr).Association("SimulationModels").Append(m).Error err = db.Model(&ic).Association("ComponentConfigurations").Append(m).Error
if err != nil { if err != nil {
return err return err
} }
// associate simulation model with scenario // associate component configuration with scenario
err = db.Model(&so).Association("SimulationModels").Append(m).Error err = db.Model(&so).Association("ComponentConfigurations").Append(m).Error
return err return err
} }
func (m *SimulationModel) Update(modifiedSimulationModel SimulationModel) error { func (m *ComponentConfiguration) Update(modifiedConfig ComponentConfiguration) error {
db := database.GetDB() db := database.GetDB()
// check if simulator has been updated // check if IC has been updated
if m.SimulatorID != modifiedSimulationModel.SimulatorID { if m.ICID != modifiedConfig.ICID {
// update simulator // update IC
var s simulator.Simulator var s infrastructure_component.InfrastructureComponent
var s_old simulator.Simulator var s_old infrastructure_component.InfrastructureComponent
err := s.ByID(modifiedSimulationModel.SimulatorID) err := s.ByID(modifiedConfig.ICID)
if err != nil { if err != nil {
return err return err
} }
err = s_old.ByID(m.SimulatorID) err = s_old.ByID(m.ICID)
if err != nil { if err != nil {
return err return err
} }
// remove simulation model from old simulator // remove component configuration from old IC
err = db.Model(&s_old).Association("SimulationModels").Delete(m).Error err = db.Model(&s_old).Association("ComponentConfigurations").Delete(m).Error
if err != nil { if err != nil {
return err return err
} }
// add simulation model to new simulator // add component configuration to new IC
err = db.Model(&s).Association("SimulationModels").Append(m).Error err = db.Model(&s).Association("ComponentConfigurations").Append(m).Error
if err != nil { if err != nil {
return err return err
} }
} }
err := db.Model(m).Updates(map[string]interface{}{ err := db.Model(m).Updates(map[string]interface{}{
"Name": modifiedSimulationModel.Name, "Name": modifiedConfig.Name,
"StartParameters": modifiedSimulationModel.StartParameters, "StartParameters": modifiedConfig.StartParameters,
"SimulatorID": modifiedSimulationModel.SimulatorID, "ICID": modifiedConfig.ICID,
"SelectedModelFileID": modifiedSimulationModel.SelectedModelFileID, "SelectedFileID": modifiedConfig.SelectedFileID,
}).Error }).Error
return err return err
} }
func (m *SimulationModel) delete() error { func (m *ComponentConfiguration) delete() error {
db := database.GetDB() db := database.GetDB()
var so scenario.Scenario var so scenario.Scenario
@ -121,9 +121,9 @@ func (m *SimulationModel) delete() error {
return err return err
} }
// remove association between SimulationModel and Scenario // remove association between ComponentConfiguration and Scenario
// SimulationModel itself is not deleted from DB, it remains as "dangling" // ComponentConfiguration itself is not deleted from DB, it remains as "dangling"
err = db.Model(&so).Association("SimulationModels").Delete(m).Error err = db.Model(&so).Association("ComponentConfigurations").Delete(m).Error
return err return err
} }

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, middleware. /** component_configuration package, middleware.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"fmt" "fmt"
@ -30,22 +30,22 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
) )
func CheckPermissions(c *gin.Context, operation database.CRUD, modelIDSource string, modelIDBody int) (bool, SimulationModel) { func CheckPermissions(c *gin.Context, operation database.CRUD, configIDSource string, configIDBody int) (bool, ComponentConfiguration) {
var m SimulationModel var m ComponentConfiguration
err := database.ValidateRole(c, database.ModelSimulationModel, operation) err := database.ValidateRole(c, database.ModelComponentConfiguration, operation)
if err != nil { if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of simulation model failed): %v", err.Error())) helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of Component Configuration failed): %v", err.Error()))
return false, m return false, m
} }
modelID, err := helper.GetIDOfElement(c, "modelID", modelIDSource, modelIDBody) configID, err := helper.GetIDOfElement(c, "configID", configIDSource, configIDBody)
if err != nil { if err != nil {
return false, m return false, m
} }
err = m.ByID(uint(modelID)) err = m.ByID(uint(configID))
if helper.DBError(c, err) { if helper.DBError(c, err) {
return false, m return false, m
} }

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, testing. /** component_configuration package, testing.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,15 +19,15 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"fmt" "fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration" "git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulator"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
@ -39,16 +39,18 @@ import (
var router *gin.Engine var router *gin.Engine
var db *gorm.DB var db *gorm.DB
var base_api_configs = "/api/configs"
var base_api_auth = "/api/authenticate"
type SimulationModelRequest struct { type ConfigRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"` ScenarioID uint `json:"scenarioID,omitempty"`
SimulatorID uint `json:"simulatorID,omitempty"` ICID uint `json:"icID,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
SelectedModelFileID uint `json:"selectedModelFileID,omitempty"` SelectedFileID uint `json:"selectedFileID,omitempty"`
} }
type SimulatorRequest struct { type ICRequest struct {
UUID string `json:"uuid,omitempty"` UUID string `json:"uuid,omitempty"`
Host string `json:"host,omitempty"` Host string `json:"host,omitempty"`
Modeltype string `json:"modelType,omitempty"` Modeltype string `json:"modelType,omitempty"`
@ -62,40 +64,40 @@ type ScenarioRequest struct {
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
} }
func addScenarioAndSimulator() (scenarioID uint, simulatorID uint) { func addScenarioAndIC() (scenarioID uint, ICID uint) {
// authenticate as admin // authenticate as admin
token, _ := helper.AuthenticateForTest(router, token, _ := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.AdminCredentials) base_api_auth, "POST", helper.AdminCredentials)
// POST $newSimulatorA // POST $newICA
newSimulatorA := SimulatorRequest{ newICA := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
_, resp, _ := helper.TestEndpoint(router, token, _, resp, _ := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulatorA}) "/api/ic", "POST", helper.KeyModels{"ic": newICA})
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, _ := helper.GetResponseID(resp) newICID, _ := helper.GetResponseID(resp)
// POST a second simulator to change to that simulator during testing // POST a second IC to change to that IC during testing
newSimulatorB := SimulatorRequest{ newICB := ICRequest{
UUID: database.SimulatorB.UUID, UUID: database.ICB.UUID,
Host: database.SimulatorB.Host, Host: database.ICB.Host,
Modeltype: database.SimulatorB.Modeltype, Modeltype: database.ICB.Modeltype,
State: database.SimulatorB.State, State: database.ICB.State,
Properties: database.SimulatorB.Properties, Properties: database.ICB.Properties,
} }
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulatorB}) "/api/ic", "POST", helper.KeyModels{"ic": newICB})
// authenticate as normal user // authenticate as normal user
token, _ = helper.AuthenticateForTest(router, token, _ = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
// POST $newScenario // POST $newScenario
newScenario := ScenarioRequest{ newScenario := ScenarioRequest{
@ -113,7 +115,7 @@ func addScenarioAndSimulator() (scenarioID uint, simulatorID uint) {
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil) fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
return uint(newScenarioID), uint(newSimulatorID) return uint(newScenarioID), uint(newICID)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -133,342 +135,342 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
RegisterSimulationModelEndpoints(api.Group("/models")) RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// scenario endpoints required here to first add a scenario to the DB // scenario endpoints required here to first add a scenario to the DB
// that can be associated with a new simulation model // that can be associated with a new component configuration
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
// simulator endpoints required here to first add a simulator to the DB // IC endpoints required here to first add a IC to the DB
// that can be associated with a new simulation model // that can be associated with a new component configuration
simulator.RegisterSimulatorEndpoints(api.Group("/simulators")) infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
os.Exit(m.Run()) os.Exit(m.Run())
} }
func TestAddSimulationModel(t *testing.T) { func TestAddConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
scenarioID, simulatorID := addScenarioAndSimulator() scenarioID, ICID := addScenarioAndIC()
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
SimulatorID: simulatorID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
// authenticate as normal userB who has no access to new scenario // authenticate as normal userB who has no access to new scenario
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to POST with no access // try to POST with no access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to POST non JSON body // try to POST non JSON body
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/models", "POST", "this is not JSON") base_api_configs, "POST", "this is not JSON")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare POST's response with the newSimulationModel // Compare POST's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp) newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// Get the newSimulationModel // Get the newConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the newSimulationModel // Compare GET's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
// try to POST a malformed simulation model // try to POST a malformed component config
// Required fields are missing // Required fields are missing
malformedNewSimulationModel := SimulationModelRequest{ malformedNewConfig := ConfigRequest{
Name: "ThisIsAMalformedRequest", Name: "ThisIsAMalformedRequest",
} }
// this should NOT work and return a unprocessable entity 442 status code // this should NOT work and return a unprocessable entity 442 status code
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": malformedNewSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": malformedNewConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal userB who has no access to new scenario // authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Try to GET the newSimulationModel with no access // Try to GET the newConfig with no access
// Should result in unprocessable entity // Should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
} }
func TestUpdateSimulationModel(t *testing.T) { func TestUpdateConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
scenarioID, simulatorID := addScenarioAndSimulator() scenarioID, ICID := addScenarioAndIC()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
SimulatorID: simulatorID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp) newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
updatedSimulationModel := SimulationModelRequest{ updatedConfig := ConfigRequest{
Name: database.SimulationModelB.Name, Name: database.ConfigB.Name,
StartParameters: database.SimulationModelB.StartParameters, StartParameters: database.ConfigB.StartParameters,
} }
// authenticate as normal userB who has no access to new scenario // authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to PUT with no access // try to PUT with no access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user who has access to simulation model // authenticate as guest user who has access to component config
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.GuestCredentials) base_api_auth, "POST", helper.GuestCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to PUT as guest // try to PUT as guest
// should NOT work and result in unprocessable entity // should NOT work and result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to PUT a non JSON body // try to PUT a non JSON body
// should result in a bad request // should result in a bad request
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", "This is not JSON") fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", "This is not JSON")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// test PUT // test PUT
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updatedSimulationModel // Compare PUT's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
//Change simulator ID to use second simulator available in DB //Change IC ID to use second IC available in DB
updatedSimulationModel.SimulatorID = simulatorID + 1 updatedConfig.ICID = ICID + 1
// test PUT again // test PUT again
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updatedSimulationModel // Compare PUT's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
// Get the updatedSimulationModel // Get the updateConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the updatedSimulationModel // Compare GET's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
// try to update a simulation model that does not exist (should return not found 404 status code) // try to update a component config that does not exist (should return not found 404 status code)
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID+1), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID+1), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp) assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
} }
func TestDeleteSimulationModel(t *testing.T) { func TestDeleteConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
scenarioID, simulatorID := addScenarioAndSimulator() scenarioID, ICID := addScenarioAndIC()
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
SimulatorID: simulatorID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp) newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// authenticate as normal userB who has no access to new scenario // authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE with no access // try to DELETE with no access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "DELETE", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "DELETE", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all the simulation models returned for scenario // Count the number of all the component config returned for scenario
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// Delete the added newSimulationModel // Delete the added newConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "DELETE", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "DELETE", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare DELETE's response with the newSimulationModel // Compare DELETE's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
// Again count the number of all the simulation models returned // Again count the number of all the component configs returned
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber-1, finalNumber) assert.Equal(t, initialNumber-1, finalNumber)
} }
func TestGetAllSimulationModelsOfScenario(t *testing.T) { func TestGetAllConfigsOfScenario(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
scenarioID, simulatorID := addScenarioAndSimulator() scenarioID, ICID := addScenarioAndIC()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
SimulatorID: simulatorID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Count the number of all the simulation models returned for scenario // Count the number of all the component config returned for scenario
NumberOfSimulationModels, err := helper.LengthOfResponse(router, token, NumberOfConfigs, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 1, NumberOfSimulationModels) assert.Equal(t, 1, NumberOfConfigs)
// authenticate as normal userB who has no access to scenario // authenticate as normal userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to get models without access // try to get configs without access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)

View file

@ -0,0 +1,108 @@
/** component_configuration package, validators.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package component_configuration
import (
"encoding/json"
"github.com/jinzhu/gorm/dialects/postgres"
"github.com/nsf/jsondiff"
"gopkg.in/go-playground/validator.v9"
)
var validate *validator.Validate
type validNewConfig struct {
Name string `form:"Name" validate:"required"`
ScenarioID uint `form:"ScenarioID" validate:"required"`
ICID uint `form:"ICID" validate:"required"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"required"`
SelectedFileID uint `form:"SelectedFileID" validate:"omitempty"`
}
type validUpdatedConfig struct {
Name string `form:"Name" validate:"omitempty"`
ICID uint `form:"ICID" validate:"omitempty"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"omitempty"`
SelectedFileID uint `form:"SelectedFileID" validate:"omitempty"`
}
type addConfigRequest struct {
Config validNewConfig `json:"config"`
}
type updateConfigRequest struct {
Config validUpdatedConfig `json:"config"`
}
func (r *addConfigRequest) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *validUpdatedConfig) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *addConfigRequest) createConfig() ComponentConfiguration {
var s ComponentConfiguration
s.Name = r.Config.Name
s.ScenarioID = r.Config.ScenarioID
s.ICID = r.Config.ICID
s.StartParameters = r.Config.StartParameters
s.SelectedFileID = r.Config.SelectedFileID
return s
}
func (r *updateConfigRequest) updateConfig(oldConfig ComponentConfiguration) ComponentConfiguration {
// Use the old ComponentConfiguration as a basis for the updated config
s := oldConfig
if r.Config.Name != "" {
s.Name = r.Config.Name
}
if r.Config.ICID != 0 {
s.ICID = r.Config.ICID
}
if r.Config.SelectedFileID != 0 {
s.SelectedFileID = r.Config.SelectedFileID
}
// 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.Config.StartParameters)
opts := jsondiff.DefaultConsoleOptions()
diff, _ := jsondiff.Compare(emptyJson_ser, startParams_ser, &opts)
if diff.String() != "FullMatch" {
s.StartParameters = r.Config.StartParameters
}
return s
}

View file

@ -30,7 +30,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
) )
@ -43,23 +43,23 @@ func RegisterFileEndpoints(r *gin.RouterGroup) {
} }
// getFiles godoc // getFiles godoc
// @Summary Get all files of a specific model or widget // @Summary Get all files of a specific component configuration or widget
// @ID getFiles // @ID getFiles
// @Tags files // @Tags files
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseFiles "Files which belong to simulation model or widget" // @Success 200 {object} docs.ResponseFiles "Files which belong to config or widget"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param objectType query string true "Set to model for files of model, set to widget for files of widget" // @Param objectType query string true "Set to config for files of component configuration, set to widget for files of widget"
// @Param objectID query int true "ID of either model or widget of which files are requested" // @Param objectID query int true "ID of either config or widget of which files are requested"
// @Router /files [get] // @Router /files [get]
func getFiles(c *gin.Context) { func getFiles(c *gin.Context) {
var err error var err error
objectType := c.Request.URL.Query().Get("objectType") objectType := c.Request.URL.Query().Get("objectType")
if objectType != "model" && objectType != "widget" { if objectType != "config" && objectType != "widget" {
helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType)) helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType))
return return
} }
@ -72,10 +72,10 @@ func getFiles(c *gin.Context) {
//Check access //Check access
var ok bool var ok bool
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
var w widget.Widget var w widget.Widget
if objectType == "model" { if objectType == "config" {
ok, m = simulationmodel.CheckPermissions(c, database.Read, "body", objectID) ok, m = component_configuration.CheckPermissions(c, database.Read, "body", objectID)
} else { } else {
ok, w = widget.CheckPermissions(c, database.Read, objectID) ok, w = widget.CheckPermissions(c, database.Read, objectID)
} }
@ -88,7 +88,7 @@ func getFiles(c *gin.Context) {
var files []database.File var files []database.File
if objectType == "model" { if objectType == "config" {
err = db.Order("ID asc").Model(&m).Related(&files, "Files").Error err = db.Order("ID asc").Model(&m).Related(&files, "Files").Error
} else { } else {
err = db.Order("ID asc").Model(&w).Related(&files, "Files").Error err = db.Order("ID asc").Model(&w).Related(&files, "Files").Error
@ -101,7 +101,7 @@ func getFiles(c *gin.Context) {
} }
// addFile godoc // addFile godoc
// @Summary Add a file to a specific model or widget // @Summary Add a file to a specific component config or widget
// @ID addFile // @ID addFile
// @Tags files // @Tags files
// @Produce json // @Produce json
@ -118,13 +118,13 @@ func getFiles(c *gin.Context) {
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputFile formData file true "File to be uploaded" // @Param inputFile formData file true "File to be uploaded"
// @Param objectType query string true "Set to model for files of model, set to widget for files of widget" // @Param objectType query string true "Set to config for files of component config, set to widget for files of widget"
// @Param objectID query int true "ID of either model or widget of which files are requested" // @Param objectID query int true "ID of either config or widget of which files are requested"
// @Router /files [post] // @Router /files [post]
func addFile(c *gin.Context) { func addFile(c *gin.Context) {
objectType := c.Request.URL.Query().Get("objectType") objectType := c.Request.URL.Query().Get("objectType")
if objectType != "model" && objectType != "widget" { if objectType != "config" && objectType != "widget" {
helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType)) helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType))
return return
} }
@ -137,8 +137,8 @@ func addFile(c *gin.Context) {
// Check access // Check access
var ok bool var ok bool
if objectType == "model" { if objectType == "config" {
ok, _ = simulationmodel.CheckPermissions(c, database.Update, "body", objectID) ok, _ = component_configuration.CheckPermissions(c, database.Update, "body", objectID)
if !ok { if !ok {
return return
} }

View file

@ -31,7 +31,7 @@ import (
"time" "time"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
) )
@ -84,14 +84,14 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
f.ImageWidth = 0 // TODO: do we need this? f.ImageWidth = 0 // TODO: do we need this?
f.ImageHeight = 0 // TODO: do we need this? f.ImageHeight = 0 // TODO: do we need this?
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
var w widget.Widget var w widget.Widget
var err error var err error
if objectType == "model" { if objectType == "config" {
// check if model exists // check if config exists
err = m.ByID(objectID) err = m.ByID(objectID)
f.WidgetID = 0 f.WidgetID = 0
f.SimulationModelID = objectID f.ConfigID = objectID
if err != nil { if err != nil {
return err return err
} }
@ -99,7 +99,7 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
} else { } else {
// check if widget exists // check if widget exists
f.WidgetID = objectID f.WidgetID = objectID
f.SimulationModelID = 0 f.ConfigID = 0
err = w.ByID(uint(objectID)) err = w.ByID(uint(objectID))
if err != nil { if err != nil {
return err return err
@ -122,8 +122,8 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
return err return err
} }
// Create association to model or widget // Create association to config or widget
if objectType == "model" { if objectType == "config" {
db := database.GetDB() db := database.GetDB()
err := db.Model(&m).Association("Files").Append(f).Error err := db.Model(&m).Association("Files").Append(f).Error
if err != nil { if err != nil {
@ -174,9 +174,9 @@ func (f *File) delete() error {
return err return err
} }
} else { } else {
// remove association between file and simulation model // remove association between file and config
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
err := m.ByID(f.SimulationModelID) err := m.ByID(f.ConfigID)
if err != nil { if err != nil {
return err return err
} }

View file

@ -25,7 +25,7 @@ import (
"fmt" "fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -50,8 +50,8 @@ func checkPermissions(c *gin.Context, operation database.CRUD) (bool, File) {
return false, f return false, f
} }
if f.SimulationModelID > 0 { if f.ConfigID > 0 {
ok, _ := simulationmodel.CheckPermissions(c, operation, "body", int(f.SimulationModelID)) ok, _ := component_configuration.CheckPermissions(c, operation, "body", int(f.ConfigID))
if !ok { if !ok {
return false, f return false, f
} }

View file

@ -27,10 +27,10 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration" "git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulator"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -49,14 +49,14 @@ import (
var router *gin.Engine var router *gin.Engine
var db *gorm.DB var db *gorm.DB
type SimulationModelRequest struct { type ConfigRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"` ScenarioID uint `json:"scenarioID,omitempty"`
SimulatorID uint `json:"simulatorID,omitempty"` ICID uint `json:"icID,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
} }
type SimulatorRequest struct { type ICRequest struct {
UUID string `json:"uuid,omitempty"` UUID string `json:"uuid,omitempty"`
Host string `json:"host,omitempty"` Host string `json:"host,omitempty"`
Modeltype string `json:"modelType,omitempty"` Modeltype string `json:"modelType,omitempty"`
@ -91,25 +91,25 @@ type WidgetRequest struct {
CustomProperties postgres.Jsonb `json:"customProperties,omitempty"` CustomProperties postgres.Jsonb `json:"customProperties,omitempty"`
} }
func addScenarioAndSimulatorAndSimulationModelAndDashboardAndWidget() (scenarioID uint, simulatorID uint, simulationModelID uint, dashboardID uint, widgetID uint) { func addScenarioAndICAndConfigAndDashboardAndWidget() (scenarioID uint, ICID uint, configID uint, dashboardID uint, widgetID uint) {
// authenticate as admin // authenticate as admin
token, _ := helper.AuthenticateForTest(router, token, _ := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
// POST $newSimulatorA // POST $newICA
newSimulatorA := SimulatorRequest{ newICA := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
_, resp, _ := helper.TestEndpoint(router, token, _, resp, _ := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulatorA}) "/api/ic", "POST", helper.KeyModels{"ic": newICA})
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, _ := helper.GetResponseID(resp) newICID, _ := helper.GetResponseID(resp)
// authenticate as normal user // authenticate as normal user
token, _ = helper.AuthenticateForTest(router, token, _ = helper.AuthenticateForTest(router,
@ -127,18 +127,18 @@ func addScenarioAndSimulatorAndSimulationModelAndDashboardAndWidget() (scenarioI
// Read newScenario's ID from the response // Read newScenario's ID from the response
newScenarioID, _ := helper.GetResponseID(resp) newScenarioID, _ := helper.GetResponseID(resp)
// POST new simulation model // POST new component config
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: uint(newScenarioID), ScenarioID: uint(newScenarioID),
SimulatorID: uint(newSimulatorID), ICID: uint(newICID),
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
} }
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) "/api/configs", "POST", helper.KeyModels{"config": newConfig})
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, _ := helper.GetResponseID(resp) newConfigID, _ := helper.GetResponseID(resp)
// POST new dashboard // POST new dashboard
newDashboard := DashboardRequest{ newDashboard := DashboardRequest{
@ -177,7 +177,7 @@ func addScenarioAndSimulatorAndSimulationModelAndDashboardAndWidget() (scenarioI
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil) fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
return uint(newScenarioID), uint(newSimulatorID), uint(newSimulationModelID), uint(newDashboardID), uint(newWidgetID) return uint(newScenarioID), uint(newICID), uint(newConfigID), uint(newDashboardID), uint(newWidgetID)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -196,15 +196,15 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
// simulationmodel endpoints required here to first add a simulation to the DB // component-configuration endpoints required here to first add a config to the DB
// that can be associated with a new file // that can be associated with a new file
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models")) component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// scenario endpoints required here to first add a scenario to the DB // scenario endpoints required here to first add a scenario to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
// simulator endpoints required here to first add a simulator to the DB // IC endpoints required here to first add a IC to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
simulator.RegisterSimulatorEndpoints(api.Group("/simulators")) infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
// dashboard endpoints required here to first add a dashboard to the DB // dashboard endpoints required here to first add a dashboard to the DB
// that can be associated with a new widget // that can be associated with a new widget
dashboard.RegisterDashboardEndpoints(api.Group("/dashboards")) dashboard.RegisterDashboardEndpoints(api.Group("/dashboards"))
@ -224,7 +224,7 @@ func TestAddFile(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndSimulatorAndSimulationModelAndDashboardAndWidget() _, _, configID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as userB who has no access to the elements in the DB // authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -233,10 +233,10 @@ func TestAddFile(t *testing.T) {
emptyBuf := &bytes.Buffer{} emptyBuf := &bytes.Buffer{}
// try to POST to a simulation model to which UserB has no access // try to POST to a component config to which UserB has no access
// should return a 422 unprocessable entity error // should return a 422 unprocessable entity error
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "POST", emptyBuf) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "POST", emptyBuf)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
@ -262,14 +262,14 @@ func TestAddFile(t *testing.T) {
// try to POST without an object ID // try to POST without an object ID
// should return a bad request error // should return a bad request error
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectType=model"), "POST", emptyBuf) fmt.Sprintf("/api/files?objectType=config"), "POST", emptyBuf)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// try to POST an invalid file // try to POST an invalid file
// should return a bad request // should return a bad request
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "POST", emptyBuf) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "POST", emptyBuf)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
@ -299,7 +299,7 @@ func TestAddFile(t *testing.T) {
// Create the request // Create the request
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBuf) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), bodyBuf)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentType) req.Header.Set("Content-Type", contentType)
@ -340,7 +340,7 @@ func TestUpdateFile(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, _ := addScenarioAndSimulatorAndSimulationModelAndDashboardAndWidget() _, _, configID, _, _ := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -372,7 +372,7 @@ func TestUpdateFile(t *testing.T) {
// Create the POST request // Create the POST request
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBuf) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), bodyBuf)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentType) req.Header.Set("Content-Type", contentType)
@ -474,7 +474,7 @@ func TestDeleteFile(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndSimulatorAndSimulationModelAndDashboardAndWidget() _, _, configID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -504,7 +504,7 @@ func TestDeleteFile(t *testing.T) {
// Create the request // Create the request
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBuf) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), bodyBuf)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentType) req.Header.Set("Content-Type", contentType)
req.Header.Add("Authorization", "Bearer "+token) req.Header.Add("Authorization", "Bearer "+token)
@ -542,7 +542,7 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.UserBCredentials) "/api/authenticate", "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE file of simulation model to which userB has no access // try to DELETE file of component config to which userB has no access
// should return an unprocessable entity error // should return an unprocessable entity error
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil) fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil)
@ -561,9 +561,9 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all files returned for simulation model // Count the number of all files returned for component config
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE non-existing fileID // try to DELETE non-existing fileID
@ -578,7 +578,7 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.GuestCredentials) "/api/authenticate", "POST", helper.GuestCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE file of simulation model as guest // try to DELETE file of component config as guest
// should return an unprocessable entity error // should return an unprocessable entity error
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil) fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil)
@ -609,15 +609,15 @@ func TestDeleteFile(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Again count the number of all the files returned for simulation model // Again count the number of all the files returned for component config
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber-1, finalNumber) assert.Equal(t, initialNumber-1, finalNumber)
} }
func TestGetAllFilesOfSimulationModel(t *testing.T) { func TestGetAllFilesOfConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
@ -625,17 +625,17 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndSimulatorAndSimulationModelAndDashboardAndWidget() _, _, ConfigID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as userB who has no access to the elements in the DB // authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) "/api/authenticate", "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to get all files for simulation model to which userB has not access // try to get all files for component config to which userB has not access
// should return unprocessable entity error // should return unprocessable entity error
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
@ -653,19 +653,19 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
//try to get all files for unsupported object type; should return a bad request error //try to get all files for unsupported object type; should return a bad request error
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=wrongtype", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=wrongtype", ConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
//try to get all files with missing object ID; should return a bad request error //try to get all files with missing object ID; should return a bad request error
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectType=model"), "GET", nil) fmt.Sprintf("/api/files?objectType=config"), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// Count the number of all files returned for simulation model // Count the number of all files returned for component config
initialNumberModel, err := helper.LengthOfResponse(router, token, initialNumberConfig, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all files returned for widget // Count the number of all files returned for widget
@ -683,30 +683,30 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
assert.NoError(t, err, "opening file") assert.NoError(t, err, "opening file")
defer fh.Close() defer fh.Close()
// test POST a file to simulation model and widget // test POST a file to component config and widget
bodyBufModel1 := &bytes.Buffer{} bodyBufConfig1 := &bytes.Buffer{}
bodyBufWidget1 := &bytes.Buffer{} bodyBufWidget1 := &bytes.Buffer{}
bodyWriterModel1 := multipart.NewWriter(bodyBufModel1) bodyWriterConfig1 := multipart.NewWriter(bodyBufConfig1)
bodyWriterWidget1 := multipart.NewWriter(bodyBufWidget1) bodyWriterWidget1 := multipart.NewWriter(bodyBufWidget1)
fileWriterModel1, err := bodyWriterModel1.CreateFormFile("file", "testuploadfile.txt") fileWriterConfig1, err := bodyWriterConfig1.CreateFormFile("file", "testuploadfile.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
fileWriterWidget1, err := bodyWriterWidget1.CreateFormFile("file", "testuploadfile.txt") fileWriterWidget1, err := bodyWriterWidget1.CreateFormFile("file", "testuploadfile.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
// io copy // io copy
_, err = io.Copy(fileWriterModel1, fh) _, err = io.Copy(fileWriterConfig1, fh)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
_, err = io.Copy(fileWriterWidget1, fh) _, err = io.Copy(fileWriterWidget1, fh)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
contentTypeModel1 := bodyWriterModel1.FormDataContentType() contentTypeConfig1 := bodyWriterConfig1.FormDataContentType()
contentTypeWidget1 := bodyWriterWidget1.FormDataContentType() contentTypeWidget1 := bodyWriterWidget1.FormDataContentType()
bodyWriterModel1.Close() bodyWriterConfig1.Close()
bodyWriterWidget1.Close() bodyWriterWidget1.Close()
// Create the request for simulation model // Create the request for component config
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBufModel1) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), bodyBufConfig1)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentTypeModel1) req.Header.Set("Content-Type", contentTypeConfig1)
req.Header.Add("Authorization", "Bearer "+token) req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
assert.Equalf(t, 200, w.Code, "Response body: \n%v\n", w.Body) assert.Equalf(t, 200, w.Code, "Response body: \n%v\n", w.Body)
@ -720,36 +720,36 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
router.ServeHTTP(w2, req2) router.ServeHTTP(w2, req2)
assert.Equalf(t, 200, w2.Code, "Response body: \n%v\n", w2.Body) assert.Equalf(t, 200, w2.Code, "Response body: \n%v\n", w2.Body)
// POST a second file to simulation model and widget // POST a second file to component config and widget
// open a second file handle // open a second file handle
fh2, err := os.Open("testfile.txt") fh2, err := os.Open("testfile.txt")
assert.NoError(t, err, "opening file") assert.NoError(t, err, "opening file")
defer fh2.Close() defer fh2.Close()
bodyBufModel2 := &bytes.Buffer{} bodyBufConfig2 := &bytes.Buffer{}
bodyBufWidget2 := &bytes.Buffer{} bodyBufWidget2 := &bytes.Buffer{}
bodyWriterModel2 := multipart.NewWriter(bodyBufModel2) bodyWriterConfig2 := multipart.NewWriter(bodyBufConfig2)
bodyWriterWidget2 := multipart.NewWriter(bodyBufWidget2) bodyWriterWidget2 := multipart.NewWriter(bodyBufWidget2)
fileWriterModel2, err := bodyWriterModel2.CreateFormFile("file", "testuploadfile2.txt") fileWriterConfig2, err := bodyWriterConfig2.CreateFormFile("file", "testuploadfile2.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
fileWriterWidget2, err := bodyWriterWidget2.CreateFormFile("file", "testuploadfile2.txt") fileWriterWidget2, err := bodyWriterWidget2.CreateFormFile("file", "testuploadfile2.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
// io copy // io copy
_, err = io.Copy(fileWriterModel2, fh2) _, err = io.Copy(fileWriterConfig2, fh2)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
_, err = io.Copy(fileWriterWidget2, fh2) _, err = io.Copy(fileWriterWidget2, fh2)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
contentTypeModel2 := bodyWriterModel2.FormDataContentType() contentTypeConfig2 := bodyWriterConfig2.FormDataContentType()
contentTypeWidget2 := bodyWriterWidget2.FormDataContentType() contentTypeWidget2 := bodyWriterWidget2.FormDataContentType()
bodyWriterModel2.Close() bodyWriterConfig2.Close()
bodyWriterWidget2.Close() bodyWriterWidget2.Close()
w3 := httptest.NewRecorder() w3 := httptest.NewRecorder()
req3, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBufModel2) req3, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), bodyBufConfig2)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req3.Header.Set("Content-Type", contentTypeModel2) req3.Header.Set("Content-Type", contentTypeConfig2)
req3.Header.Add("Authorization", "Bearer "+token) req3.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w3, req3) router.ServeHTTP(w3, req3)
assert.Equalf(t, 200, w3.Code, "Response body: \n%v\n", w3.Body) assert.Equalf(t, 200, w3.Code, "Response body: \n%v\n", w3.Body)
@ -762,11 +762,11 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
router.ServeHTTP(w4, req4) router.ServeHTTP(w4, req4)
assert.Equalf(t, 200, w4.Code, "Response body: \n%v\n", w4.Body) assert.Equalf(t, 200, w4.Code, "Response body: \n%v\n", w4.Body)
// Again count the number of all the files returned for simulation model // Again count the number of all the files returned for component config
finalNumberModel, err := helper.LengthOfResponse(router, token, finalNumberConfig, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumberModel+2, finalNumberModel) assert.Equal(t, initialNumberConfig+2, finalNumberConfig)
// Again count the number of all the files returned for widget // Again count the number of all the files returned for widget
finalNumberWidget, err := helper.LengthOfResponse(router, token, finalNumberWidget, err := helper.LengthOfResponse(router, token,

View file

@ -1,4 +1,4 @@
/** Simulator package, endpoints. /** InfrastructureComponent package, endpoints.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulator package infrastructure_component
import ( import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
@ -29,61 +29,61 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
) )
func RegisterSimulatorEndpoints(r *gin.RouterGroup) { func RegisterICEndpoints(r *gin.RouterGroup) {
r.GET("", getSimulators) r.GET("", getICs)
r.POST("", addSimulator) r.POST("", addIC)
r.PUT("/:simulatorID", updateSimulator) r.PUT("/:ICID", updateIC)
r.GET("/:simulatorID", getSimulator) r.GET("/:ICID", getIC)
r.DELETE("/:simulatorID", deleteSimulator) r.DELETE("/:ICID", deleteIC)
r.GET("/:simulatorID/models", getModelsOfSimulator) r.GET("/:ICID/configs", getConfigsOfIC)
} }
// getSimulators godoc // getICs godoc
// @Summary Get all simulators // @Summary Get all infrastructure components
// @ID getSimulators // @ID getICs
// @Tags simulators // @Tags infrastructure-components
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulators "Simulators requested" // @Success 200 {object} docs.ResponseICs "ICs requested"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Router /simulators [get] // @Router /ic [get]
func getSimulators(c *gin.Context) { func getICs(c *gin.Context) {
// Checking permission is not required here since READ access is independent of user's role // Checking permission is not required here since READ access is independent of user's role
db := database.GetDB() db := database.GetDB()
var simulators []database.Simulator var ics []database.InfrastructureComponent
err := db.Order("ID asc").Find(&simulators).Error err := db.Order("ID asc").Find(&ics).Error
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulators": simulators}) c.JSON(http.StatusOK, gin.H{"ics": ics})
} }
} }
// addSimulator godoc // addIC godoc
// @Summary Add a simulator // @Summary Add an infrastructure component
// @ID addSimulator // @ID addIC
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Tags simulators // @Tags infrastructure-components
// @Success 200 {object} docs.ResponseSimulator "Simulator that was added" // @Success 200 {object} docs.ResponseIC "Infrastructure Component that was added"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSimulator body simulator.addSimulatorRequest true "Simulator to be added" // @Param inputIC body infrastructure_component.addICRequest true "Infrastructure Component to be added"
// @Router /simulators [post] // @Router /ic [post]
func addSimulator(c *gin.Context) { func addIC(c *gin.Context) {
ok, _ := CheckPermissions(c, database.ModelSimulator, database.Create, false) ok, _ := CheckPermissions(c, database.ModelInfrastructureComponent, database.Create, false)
if !ok { if !ok {
return return
} }
var req addSimulatorRequest var req addICRequest
err := c.BindJSON(&req) err := c.BindJSON(&req)
if err != nil { if err != nil {
helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error())
@ -96,40 +96,40 @@ func addSimulator(c *gin.Context) {
return return
} }
// Create the new simulator from the request // Create the new IC from the request
newSimulator := req.createSimulator() newIC := req.createIC()
// Save new simulator to DB // Save new IC to DB
err = newSimulator.save() err = newIC.save()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulator": newSimulator.Simulator}) c.JSON(http.StatusOK, gin.H{"ic": newIC.InfrastructureComponent})
} }
} }
// updateSimulator godoc // updateIC godoc
// @Summary Update a simulator // @Summary Update an infrastructure component
// @ID updateSimulator // @ID updateIC
// @Tags simulators // @Tags infrastructure-components
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulator "Simulator that was updated" // @Success 200 {object} docs.ResponseIC "Infrastructure Component that was updated"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSimulator body simulator.updateSimulatorRequest true "Simulator to be updated" // @Param inputIC body infrastructure_component.updateICRequest true "InfrastructureComponent to be updated"
// @Param simulatorID path int true "Simulator ID" // @Param ICID path int true "InfrastructureComponent ID"
// @Router /simulators/{simulatorID} [put] // @Router /ic/{ICID} [put]
func updateSimulator(c *gin.Context) { func updateIC(c *gin.Context) {
ok, oldSimulator := CheckPermissions(c, database.ModelSimulator, database.Update, true) ok, oldIC := CheckPermissions(c, database.ModelInfrastructureComponent, database.Update, true)
if !ok { if !ok {
return return
} }
var req updateSimulatorRequest var req updateICRequest
err := c.BindJSON(&req) err := c.BindJSON(&req)
if err != nil { if err != nil {
helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error())
@ -137,97 +137,97 @@ func updateSimulator(c *gin.Context) {
} }
// Validate the request // Validate the request
if err = req.Simulator.validate(); err != nil { if err = req.InfrastructureComponent.validate(); err != nil {
helper.UnprocessableEntityError(c, err.Error()) helper.UnprocessableEntityError(c, err.Error())
return return
} }
// Create the updatedSimulator from oldSimulator // Create the updatedIC from oldIC
updatedSimulator := req.updatedSimulator(oldSimulator) updatedIC := req.updatedIC(oldIC)
// Finally update the simulator in the DB // Finally update the IC in the DB
err = oldSimulator.update(updatedSimulator) err = oldIC.update(updatedIC)
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulator": updatedSimulator.Simulator}) c.JSON(http.StatusOK, gin.H{"ic": updatedIC.InfrastructureComponent})
} }
} }
// getSimulator godoc // getIC godoc
// @Summary Get simulator // @Summary Get infrastructure component
// @ID getSimulator // @ID getIC
// @Produce json // @Produce json
// @Tags simulators // @Tags infrastructure-components
// @Success 200 {object} docs.ResponseSimulator "Simulator that was requested" // @Success 200 {object} docs.ResponseIC "Infrastructure Component that was requested"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param simulatorID path int true "Simulator ID" // @Param ICID path int true "Infrastructure Component ID"
// @Router /simulators/{simulatorID} [get] // @Router /ic/{ICID} [get]
func getSimulator(c *gin.Context) { func getIC(c *gin.Context) {
ok, s := CheckPermissions(c, database.ModelSimulator, database.Read, true) ok, s := CheckPermissions(c, database.ModelInfrastructureComponent, database.Read, true)
if !ok { if !ok {
return return
} }
c.JSON(http.StatusOK, gin.H{"simulator": s.Simulator}) c.JSON(http.StatusOK, gin.H{"ic": s.InfrastructureComponent})
} }
// deleteSimulator godoc // deleteIC godoc
// @Summary Delete a simulator // @Summary Delete an infrastructure component
// @ID deleteSimulator // @ID deleteIC
// @Tags simulators // @Tags infrastructure-components
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulator "Simulator that was deleted" // @Success 200 {object} docs.ResponseIC "Infrastructure Component that was deleted"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param simulatorID path int true "Simulator ID" // @Param ICID path int true "Infrastructure Component ID"
// @Router /simulators/{simulatorID} [delete] // @Router /ic/{ICID} [delete]
func deleteSimulator(c *gin.Context) { func deleteIC(c *gin.Context) {
ok, s := CheckPermissions(c, database.ModelSimulator, database.Delete, true) ok, s := CheckPermissions(c, database.ModelInfrastructureComponent, database.Delete, true)
if !ok { if !ok {
return return
} }
// Delete the simulator // Delete the IC
err := s.delete() err := s.delete()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulator": s.Simulator}) c.JSON(http.StatusOK, gin.H{"ic": s.InfrastructureComponent})
} }
} }
// getModelsOfSimulator godoc // getConfigsOfIC godoc
// @Summary Get all simulation models in which the simulator is used // @Summary Get all configurations of the infrastructure component
// @ID getModelsOfSimulator // @ID getConfigsOfIC
// @Tags simulators // @Tags infrastructure-components
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModels "Simulation models requested by user" // @Success 200 {object} docs.ResponseConfigs "Configs requested by user"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param simulatorID path int true "Simulator ID" // @Param ICID path int true "Infrastructure Component ID"
// @Router /simulators/{simulatorID}/models [get] // @Router /ic/{ICID}/configs [get]
func getModelsOfSimulator(c *gin.Context) { func getConfigsOfIC(c *gin.Context) {
ok, s := CheckPermissions(c, database.ModelSimulator, database.Read, true) ok, s := CheckPermissions(c, database.ModelInfrastructureComponent, database.Read, true)
if !ok { if !ok {
return return
} }
// get all associated simulation models // get all associated configurations
allModels, _, err := s.getModels() allConfigs, _, err := s.getConfigs()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModels": allModels}) c.JSON(http.StatusOK, gin.H{"configs": allConfigs})
} }
} }

View file

@ -1,4 +1,4 @@
/** Simulator package, methods. /** InfrastructureComponent package, methods.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulator package infrastructure_component
import ( import (
"fmt" "fmt"
@ -27,47 +27,47 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
) )
type Simulator struct { type InfrastructureComponent struct {
database.Simulator database.InfrastructureComponent
} }
func (s *Simulator) save() error { func (s *InfrastructureComponent) save() error {
db := database.GetDB() db := database.GetDB()
err := db.Create(s).Error err := db.Create(s).Error
return err return err
} }
func (s *Simulator) ByID(id uint) error { func (s *InfrastructureComponent) ByID(id uint) error {
db := database.GetDB() db := database.GetDB()
err := db.Find(s, id).Error err := db.Find(s, id).Error
return err return err
} }
func (s *Simulator) update(updatedSimulator Simulator) error { func (s *InfrastructureComponent) update(updatedIC InfrastructureComponent) error {
db := database.GetDB() db := database.GetDB()
err := db.Model(s).Updates(updatedSimulator).Error err := db.Model(s).Updates(updatedIC).Error
return err return err
} }
func (s *Simulator) delete() error { func (s *InfrastructureComponent) delete() error {
db := database.GetDB() db := database.GetDB()
no_simulationmodels := db.Model(s).Association("SimulationModels").Count() no_configs := db.Model(s).Association("ComponentConfigurations").Count()
if no_simulationmodels > 0 { if no_configs > 0 {
return fmt.Errorf("Simulator cannot be deleted as it is still used in SimulationModels (active or dangling)") return fmt.Errorf("Infrastructure Component cannot be deleted as it is still used in configurations (active or dangling)")
} }
// delete Simulator from DB (does NOT remain as dangling) // delete InfrastructureComponent from DB (does NOT remain as dangling)
err := db.Delete(s).Error err := db.Delete(s).Error
return err return err
} }
func (s *Simulator) getModels() ([]database.SimulationModel, int, error) { func (s *InfrastructureComponent) getConfigs() ([]database.ComponentConfiguration, int, error) {
db := database.GetDB() db := database.GetDB()
var models []database.SimulationModel var configs []database.ComponentConfiguration
err := db.Order("ID asc").Model(s).Related(&models, "SimulationModels").Error err := db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
return models, len(models), err return configs, len(configs), err
} }

View file

@ -1,4 +1,4 @@
/** Simulator package, middleware. /** InfrastructureComponent package, middleware.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulator package infrastructure_component
import ( import (
"fmt" "fmt"
@ -28,24 +28,24 @@ import (
"github.com/gin-gonic/gin" "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, InfrastructureComponent) {
var s Simulator var s InfrastructureComponent
err := database.ValidateRole(c, modeltype, operation) err := database.ValidateRole(c, modeltype, operation)
if err != nil { if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of simulator failed): %v", err.Error())) helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of infrastructure component failed): %v", err.Error()))
return false, s return false, s
} }
if hasID { if hasID {
// Get the ID of the simulator from the context // Get the ID of the infrastructure component from the context
simulatorID, err := helper.GetIDOfElement(c, "simulatorID", "path", -1) ICID, err := helper.GetIDOfElement(c, "ICID", "path", -1)
if err != nil { if err != nil {
return false, s return false, s
} }
err = s.ByID(uint(simulatorID)) err = s.ByID(uint(ICID))
if helper.DBError(c, err) { if helper.DBError(c, err) {
return false, s return false, s
} }

View file

@ -1,4 +1,4 @@
/** Simulator package, testing. /** InfrastructureComponent package, testing.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulator package infrastructure_component
import ( import (
"fmt" "fmt"
@ -40,7 +40,7 @@ import (
var router *gin.Engine var router *gin.Engine
var db *gorm.DB var db *gorm.DB
type SimulatorRequest struct { type ICRequest struct {
UUID string `json:"uuid,omitempty"` UUID string `json:"uuid,omitempty"`
Host string `json:"host,omitempty"` Host string `json:"host,omitempty"`
Modeltype string `json:"modelType,omitempty"` Modeltype string `json:"modelType,omitempty"`
@ -65,12 +65,12 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
RegisterSimulatorEndpoints(api.Group("/simulators")) RegisterICEndpoints(api.Group("/ic"))
os.Exit(m.Run()) os.Exit(m.Run())
} }
func TestAddSimulatorAsAdmin(t *testing.T) { func TestAddICAsAdmin(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -83,61 +83,61 @@ func TestAddSimulatorAsAdmin(t *testing.T) {
// try to POST with non JSON body // try to POST with non JSON body
// should result in bad request // should result in bad request
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", "This is no JSON") "/api/ic", "POST", "This is no JSON")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// try to POST malformed simulator (required fields missing, validation should fail) // try to POST malformed IC (required fields missing, validation should fail)
// should result in an unprocessable entity // should result in an unprocessable entity
newMalformedSimulator := SimulatorRequest{ newMalformedIC := ICRequest{
UUID: database.SimulatorB.UUID, UUID: database.ICB.UUID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newMalformedSimulator}) "/api/ic", "POST", helper.KeyModels{"ic": newMalformedIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// test POST simulators/ $newSimulator // test POST ic/ $newIC
newSimulator := SimulatorRequest{ newIC := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulator}) "/api/ic", "POST", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare POST's response with the newSimulator // Compare POST's response with the newIC
err = helper.CompareResponse(resp, helper.KeyModels{"simulator": newSimulator}) err = helper.CompareResponse(resp, helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, err := helper.GetResponseID(resp) newICID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// Get the newSimulator // Get the newIC
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "GET", nil) fmt.Sprintf("/api/ic/%v", newICID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the newSimulator // Compare GET's response with the newIC
err = helper.CompareResponse(resp, helper.KeyModels{"simulator": newSimulator}) err = helper.CompareResponse(resp, helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
// Try to GET a simulator that does not exist // Try to GET a IC that does not exist
// should result in not found // should result in not found
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID+1), "GET", nil) fmt.Sprintf("/api/ic/%v", newICID+1), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp) assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
} }
func TestAddSimulatorAsUser(t *testing.T) { func TestAddICAsUser(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -147,24 +147,24 @@ func TestAddSimulatorAsUser(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST simulators/ $newSimulator // test POST ic/ $newIC
newSimulator := SimulatorRequest{ newIC := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
// This should fail with unprocessable entity 422 error code // This should fail with unprocessable entity 422 error code
// Normal users are not allowed to add simulators // Normal users are not allowed to add ICs
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulator}) "/api/ic", "POST", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
} }
func TestUpdateSimulatorAsAdmin(t *testing.T) { func TestUpdateICAsAdmin(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -174,59 +174,59 @@ func TestUpdateSimulatorAsAdmin(t *testing.T) {
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST simulators/ $newSimulator // test POST ic/ $newIC
newSimulator := SimulatorRequest{ newIC := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulator}) "/api/ic", "POST", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare POST's response with the newSimulator // Compare POST's response with the newIC
err = helper.CompareResponse(resp, helper.KeyModels{"simulator": newSimulator}) err = helper.CompareResponse(resp, helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, err := helper.GetResponseID(resp) newICID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// try to PUT with non JSON body // try to PUT with non JSON body
// should result in bad request // should result in bad request
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "PUT", "This is no JSON") fmt.Sprintf("/api/ic/%v", newICID), "PUT", "This is no JSON")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// Test PUT simulators // Test PUT IC
newSimulator.Host = "ThisIsMyNewHost" newIC.Host = "ThisIsMyNewHost"
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "PUT", helper.KeyModels{"simulator": newSimulator}) fmt.Sprintf("/api/ic/%v", newICID), "PUT", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updated newSimulator // Compare PUT's response with the updated newIC
err = helper.CompareResponse(resp, helper.KeyModels{"simulator": newSimulator}) err = helper.CompareResponse(resp, helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
// Get the updated newSimulator // Get the updated newIC
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "GET", nil) fmt.Sprintf("/api/ic/%v", newICID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the updated newSimulator // Compare GET's response with the updated newIC
err = helper.CompareResponse(resp, helper.KeyModels{"simulator": newSimulator}) err = helper.CompareResponse(resp, helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
} }
func TestUpdateSimulatorAsUser(t *testing.T) { func TestUpdateICAsUser(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -236,21 +236,21 @@ func TestUpdateSimulatorAsUser(t *testing.T) {
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST simulators/ $newSimulator // test POST ic/ $newIC
newSimulator := SimulatorRequest{ newIC := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulator}) "/api/ic", "POST", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, err := helper.GetResponseID(resp) newICID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// authenticate as user // authenticate as user
@ -258,17 +258,17 @@ func TestUpdateSimulatorAsUser(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Test PUT simulators // Test PUT IC
// This should fail with unprocessable entity status code 422 // This should fail with unprocessable entity status code 422
newSimulator.Host = "ThisIsMyNewHost" newIC.Host = "ThisIsMyNewHost"
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "PUT", helper.KeyModels{"simulator": newSimulator}) fmt.Sprintf("/api/ic/%v", newICID), "PUT", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
} }
func TestDeleteSimulatorAsAdmin(t *testing.T) { func TestDeleteICAsAdmin(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -278,47 +278,47 @@ func TestDeleteSimulatorAsAdmin(t *testing.T) {
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST simulators/ $newSimulator // test POST ic/ $newIC
newSimulator := SimulatorRequest{ newIC := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulator}) "/api/ic", "POST", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, err := helper.GetResponseID(resp) newICID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all the simulators returned for admin // Count the number of all the ICs returned for admin
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
"/api/simulators", "GET", nil) "/api/ic", "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// Delete the added newSimulator // Delete the added newIC
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "DELETE", nil) fmt.Sprintf("/api/ic/%v", newICID), "DELETE", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare DELETE's response with the newSimulator // Compare DELETE's response with the newIC
err = helper.CompareResponse(resp, helper.KeyModels{"simulator": newSimulator}) err = helper.CompareResponse(resp, helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
// Again count the number of all the simulators returned // Again count the number of all the ICs returned
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
"/api/simulators", "GET", nil) "/api/ic", "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, finalNumber, initialNumber-1) assert.Equal(t, finalNumber, initialNumber-1)
} }
func TestDeleteSimulatorAsUser(t *testing.T) { func TestDeleteICAsUser(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -328,21 +328,21 @@ func TestDeleteSimulatorAsUser(t *testing.T) {
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST simulators/ $newSimulator // test POST ic/ $newIC
newSimulator := SimulatorRequest{ newIC := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulator}) "/api/ic", "POST", helper.KeyModels{"ic": newIC})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, err := helper.GetResponseID(resp) newICID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// authenticate as user // authenticate as user
@ -350,16 +350,16 @@ func TestDeleteSimulatorAsUser(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Test DELETE simulators // Test DELETE ICs
// This should fail with unprocessable entity status code 422 // This should fail with unprocessable entity status code 422
newSimulator.Host = "ThisIsMyNewHost" newIC.Host = "ThisIsMyNewHost"
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v", newSimulatorID), "DELETE", nil) fmt.Sprintf("/api/ic/%v", newICID), "DELETE", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
} }
func TestGetAllSimulators(t *testing.T) { func TestGetAllICs(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -369,40 +369,40 @@ func TestGetAllSimulators(t *testing.T) {
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// get the length of the GET all simulators response for user // get the length of the GET all ICs response for user
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
"/api/simulators", "GET", nil) "/api/ic", "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// test POST simulators/ $newSimulatorA // test POST ic/ $newICA
newSimulatorA := SimulatorRequest{ newICA := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulatorA}) "/api/ic", "POST", helper.KeyModels{"ic": newICA})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// test POST simulators/ $newSimulatorB // test POST ic/ $newICB
newSimulatorB := SimulatorRequest{ newICB := ICRequest{
UUID: database.SimulatorB.UUID, UUID: database.ICB.UUID,
Host: database.SimulatorB.Host, Host: database.ICB.Host,
Modeltype: database.SimulatorB.Modeltype, Modeltype: database.ICB.Modeltype,
State: database.SimulatorB.State, State: database.ICB.State,
Properties: database.SimulatorB.Properties, Properties: database.ICB.Properties,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulatorB}) "/api/ic", "POST", helper.KeyModels{"ic": newICB})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// get the length of the GET all simulators response again // get the length of the GET all ICs response again
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
"/api/simulators", "GET", nil) "/api/ic", "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, finalNumber, initialNumber+2) assert.Equal(t, finalNumber, initialNumber+2)
@ -412,15 +412,15 @@ func TestGetAllSimulators(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// get the length of the GET all simulators response again // get the length of the GET all ICs response again
finalNumber2, err := helper.LengthOfResponse(router, token, finalNumber2, err := helper.LengthOfResponse(router, token,
"/api/simulators", "GET", nil) "/api/ic", "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, finalNumber2, initialNumber+2) assert.Equal(t, finalNumber2, initialNumber+2)
} }
func TestGetSimulationModelsOfSimulator(t *testing.T) { func TestGetConfigsOfIC(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -430,50 +430,50 @@ func TestGetSimulationModelsOfSimulator(t *testing.T) {
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST simulators/ $newSimulatorA // test POST ic/ $newICA
newSimulatorA := SimulatorRequest{ newICA := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulatorA}) "/api/ic", "POST", helper.KeyModels{"ic": newICA})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, err := helper.GetResponseID(resp) newICID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// test GET simulators/ID/models // test GET ic/ID/confis
// TODO how to properly test this without using simulation model endpoints? // TODO how to properly test this without using component configuration endpoints?
numberOfModels, err := helper.LengthOfResponse(router, token, numberOfConfigs, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/simulators/%v/models", newSimulatorID), "GET", nil) fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
assert.Equal(t, 0, numberOfModels) assert.Equal(t, 0, numberOfConfigs)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test GET simulators/ID/models // test GET ic/ID/configs
// TODO how to properly test this without using simulation model endpoints? // TODO how to properly test this without using component configuration endpoints?
numberOfModels, err = helper.LengthOfResponse(router, token, numberOfConfigs, err = helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/simulators/%v/models", newSimulatorID), "GET", nil) fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
assert.Equal(t, 0, numberOfModels) assert.Equal(t, 0, numberOfConfigs)
// Try to get models of simulator that does not exist // Try to get configs of IC that does not exist
// should result in not found // should result in not found
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/simulators/%v/models", newSimulatorID+1), "GET", nil) fmt.Sprintf("/api/ic/%v/configs", newICID+1), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp) assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
} }

View file

@ -1,4 +1,4 @@
/** Simulator package, validators. /** InfrastructureComponent package, validators.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulator package infrastructure_component
import ( import (
"encoding/json" "encoding/json"
@ -30,7 +30,7 @@ import (
var validate *validator.Validate var validate *validator.Validate
type validNewSimulator struct { type validNewIC struct {
UUID string `form:"UUID" validate:"required"` UUID string `form:"UUID" validate:"required"`
Host string `form:"Host" validate:"required"` Host string `form:"Host" validate:"required"`
Modeltype string `form:"Modeltype" validate:"required"` Modeltype string `form:"Modeltype" validate:"required"`
@ -38,7 +38,7 @@ type validNewSimulator struct {
State string `form:"State"` State string `form:"State"`
} }
type validUpdatedSimulator struct { type validUpdatedIC struct {
UUID string `form:"UUID" validate:"omitempty"` UUID string `form:"UUID" validate:"omitempty"`
Host string `form:"Host" validate:"omitempty"` Host string `form:"Host" validate:"omitempty"`
Modeltype string `form:"Modeltype" validate:"omitempty"` Modeltype string `form:"Modeltype" validate:"omitempty"`
@ -46,68 +46,68 @@ type validUpdatedSimulator struct {
State string `form:"State" validate:"omitempty"` State string `form:"State" validate:"omitempty"`
} }
type addSimulatorRequest struct { type addICRequest struct {
Simulator validNewSimulator `json:"simulator"` InfrastructureComponent validNewIC `json:"ic"`
} }
type updateSimulatorRequest struct { type updateICRequest struct {
Simulator validUpdatedSimulator `json:"simulator"` InfrastructureComponent validUpdatedIC `json:"ic"`
} }
func (r *addSimulatorRequest) validate() error { func (r *addICRequest) validate() error {
validate = validator.New() validate = validator.New()
errs := validate.Struct(r) errs := validate.Struct(r)
return errs return errs
} }
func (r *validUpdatedSimulator) validate() error { func (r *validUpdatedIC) validate() error {
validate = validator.New() validate = validator.New()
errs := validate.Struct(r) errs := validate.Struct(r)
return errs return errs
} }
func (r *addSimulatorRequest) createSimulator() Simulator { func (r *addICRequest) createIC() InfrastructureComponent {
var s Simulator var s InfrastructureComponent
s.UUID = r.Simulator.UUID s.UUID = r.InfrastructureComponent.UUID
s.Host = r.Simulator.Host s.Host = r.InfrastructureComponent.Host
s.Modeltype = r.Simulator.Modeltype s.Modeltype = r.InfrastructureComponent.Modeltype
s.Properties = r.Simulator.Properties s.Properties = r.InfrastructureComponent.Properties
if r.Simulator.State != "" { if r.InfrastructureComponent.State != "" {
s.State = r.Simulator.State s.State = r.InfrastructureComponent.State
} }
return s return s
} }
func (r *updateSimulatorRequest) updatedSimulator(oldSimulator Simulator) Simulator { func (r *updateICRequest) updatedIC(oldIC InfrastructureComponent) InfrastructureComponent {
// Use the old Simulator as a basis for the updated Simulator `s` // Use the old InfrastructureComponent as a basis for the updated InfrastructureComponent `s`
s := oldSimulator s := oldIC
if r.Simulator.UUID != "" { if r.InfrastructureComponent.UUID != "" {
s.UUID = r.Simulator.UUID s.UUID = r.InfrastructureComponent.UUID
} }
if r.Simulator.Host != "" { if r.InfrastructureComponent.Host != "" {
s.Host = r.Simulator.Host s.Host = r.InfrastructureComponent.Host
} }
if r.Simulator.Modeltype != "" { if r.InfrastructureComponent.Modeltype != "" {
s.Modeltype = r.Simulator.Modeltype s.Modeltype = r.InfrastructureComponent.Modeltype
} }
if r.Simulator.State != "" { if r.InfrastructureComponent.State != "" {
s.State = r.Simulator.State s.State = r.InfrastructureComponent.State
} }
// only update props if not empty // only update props if not empty
var emptyJson postgres.Jsonb var emptyJson postgres.Jsonb
// Serialize empty json and params // Serialize empty json and params
emptyJson_ser, _ := json.Marshal(emptyJson) emptyJson_ser, _ := json.Marshal(emptyJson)
startParams_ser, _ := json.Marshal(r.Simulator.Properties) startParams_ser, _ := json.Marshal(r.InfrastructureComponent.Properties)
opts := jsondiff.DefaultConsoleOptions() opts := jsondiff.DefaultConsoleOptions()
diff, _ := jsondiff.Compare(emptyJson_ser, startParams_ser, &opts) diff, _ := jsondiff.Compare(emptyJson_ser, startParams_ser, &opts)
if diff.String() != "FullMatch" { if diff.String() != "FullMatch" {
s.Properties = r.Simulator.Properties s.Properties = r.InfrastructureComponent.Properties
} }
return s return s

View file

@ -30,17 +30,17 @@ import (
) )
var ( var (
SimulatorCounter = prometheus.NewCounter( ICCounter = prometheus.NewCounter(
prometheus.CounterOpts{ prometheus.CounterOpts{
Name: "simulators", Name: "infrastructure_components",
Help: "A counter for the total number of simulators", Help: "A counter for the total number of infrastructure_components",
}, },
) )
SimulationModelCounter = prometheus.NewCounter( ComponentConfigurationCounter = prometheus.NewCounter(
prometheus.CounterOpts{ prometheus.CounterOpts{
Name: "simulation_models", Name: "component_configurations",
Help: "A counter for the total number of simulation models", Help: "A counter for the total number of component configurations",
}, },
) )
@ -102,8 +102,8 @@ func RegisterMetricsEndpoint(rg *gin.RouterGroup) {
// Register metrics // Register metrics
prometheus.MustRegister( prometheus.MustRegister(
SimulatorCounter, ICCounter,
SimulationModelCounter, ComponentConfigurationCounter,
FileCounter, FileCounter,
ScenarioCounter, ScenarioCounter,
UserCounter, UserCounter,
@ -112,17 +112,17 @@ func RegisterMetricsEndpoint(rg *gin.RouterGroup) {
} }
func InitCounters(db *gorm.DB) { func InitCounters(db *gorm.DB) {
var simulators, simulation_models, files, scenarios, users, dashboards float64 var infrastructure_components, component_configurations, files, scenarios, users, dashboards float64
db.Table("simulators").Count(&simulators) db.Table("infrastructure_components").Count(&infrastructure_components)
db.Table("simulation_models").Count(&simulation_models) db.Table("component_configurations").Count(&component_configurations)
db.Table("files").Count(&files) db.Table("files").Count(&files)
db.Table("scenarios").Count(&scenarios) db.Table("scenarios").Count(&scenarios)
db.Table("users").Count(&users) db.Table("users").Count(&users)
db.Table("dashboards").Count(&dashboards) db.Table("dashboards").Count(&dashboards)
SimulatorCounter.Add(simulators) ICCounter.Add(infrastructure_components)
SimulationModelCounter.Add(simulation_models) ComponentConfigurationCounter.Add(component_configurations)
FileCounter.Add(files) FileCounter.Add(files)
ScenarioCounter.Add(scenarios) ScenarioCounter.Add(scenarios)
UserCounter.Add(users) UserCounter.Add(users)

View file

@ -82,7 +82,7 @@ func getScenarios(c *gin.Context) {
return return
} }
} }
// TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario // TODO return list of configIDs, dashboardIDs and userIDs per scenario
c.JSON(http.StatusOK, gin.H{"scenarios": scenarios}) c.JSON(http.StatusOK, gin.H{"scenarios": scenarios})
} }
@ -211,7 +211,7 @@ func getScenario(c *gin.Context) {
return return
} }
// TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario // TODO return list of configIDs, dashboardIDs and userIDs per scenario
c.JSON(http.StatusOK, gin.H{"scenario": so.Scenario}) c.JSON(http.StatusOK, gin.H{"scenario": so.Scenario})
} }

View file

@ -28,7 +28,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
) )
func RegisterSignalEndpoints(r *gin.RouterGroup) { func RegisterSignalEndpoints(r *gin.RouterGroup) {
@ -45,8 +45,8 @@ func RegisterSignalEndpoints(r *gin.RouterGroup) {
// @Produce json // @Produce json
// @Tags signals // @Tags signals
// @Param direction query string true "Direction of signal (in or out)" // @Param direction query string true "Direction of signal (in or out)"
// @Param modelID query string true "Model ID of signals to be obtained" // @Param configID query string true "Config ID of signals to be obtained"
// @Success 200 {object} docs.ResponseSignals "Signals which belong to simulation model" // @Success 200 {object} docs.ResponseSignals "Signals which belong to component configuration"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
@ -54,7 +54,7 @@ func RegisterSignalEndpoints(r *gin.RouterGroup) {
// @Router /signals [get] // @Router /signals [get]
func getSignals(c *gin.Context) { func getSignals(c *gin.Context) {
ok, m := simulationmodel.CheckPermissions(c, database.Read, "query", -1) ok, m := component_configuration.CheckPermissions(c, database.Read, "query", -1)
if !ok { if !ok {
return return
} }
@ -80,7 +80,7 @@ func getSignals(c *gin.Context) {
} }
// AddSignal godoc // AddSignal godoc
// @Summary Add a signal to a signal mapping of a model // @Summary Add a signal to a signal mapping of a component configuration
// @ID AddSignal // @ID AddSignal
// @Accept json // @Accept json
// @Produce json // @Produce json
@ -91,7 +91,7 @@ func getSignals(c *gin.Context) {
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSignal body signal.addSignalRequest true "A signal to be added to the model incl. direction and model ID to which signal shall be added" // @Param inputSignal body signal.addSignalRequest true "A signal to be added to the component configuration incl. direction and config ID to which signal shall be added"
// @Router /signals [post] // @Router /signals [post]
func addSignal(c *gin.Context) { func addSignal(c *gin.Context) {
@ -110,13 +110,13 @@ func addSignal(c *gin.Context) {
// Create the new signal from the request // Create the new signal from the request
newSignal := req.createSignal() newSignal := req.createSignal()
ok, _ := simulationmodel.CheckPermissions(c, database.Update, "body", int(newSignal.SimulationModelID)) ok, _ := component_configuration.CheckPermissions(c, database.Update, "body", int(newSignal.ConfigID))
if !ok { if !ok {
return return
} }
// Add signal to model // Add signal to component configuration
err := newSignal.addToSimulationModel() err := newSignal.addToConfig()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"signal": newSignal.Signal}) c.JSON(http.StatusOK, gin.H{"signal": newSignal.Signal})
} }

View file

@ -23,7 +23,7 @@ package signal
import ( import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
) )
type Signal struct { type Signal struct {
@ -45,10 +45,10 @@ func (s *Signal) byID(id uint) error {
return nil return nil
} }
func (s *Signal) addToSimulationModel() error { func (s *Signal) addToConfig() error {
db := database.GetDB() db := database.GetDB()
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
err := m.ByID(s.SimulationModelID) err := m.ByID(s.ConfigID)
if err != nil { if err != nil {
return err return err
} }
@ -59,7 +59,7 @@ func (s *Signal) addToSimulationModel() error {
return err return err
} }
// associate signal with simulation model in correct direction // associate signal with component configuration in correct direction
if s.Direction == "in" { if s.Direction == "in" {
err = db.Model(&m).Association("InputMapping").Append(s).Error err = db.Model(&m).Association("InputMapping").Append(s).Error
if err != nil { if err != nil {
@ -99,13 +99,13 @@ func (s *Signal) update(modifiedSignal Signal) error {
func (s *Signal) delete() error { func (s *Signal) delete() error {
db := database.GetDB() db := database.GetDB()
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
err := m.ByID(s.SimulationModelID) err := m.ByID(s.ConfigID)
if err != nil { if err != nil {
return err return err
} }
// remove association between Signal and SimulationModel // remove association between Signal and ComponentConfiguration
// Signal itself is not deleted from DB, it remains as "dangling" // Signal itself is not deleted from DB, it remains as "dangling"
if s.Direction == "in" { if s.Direction == "in" {
err = db.Model(&m).Association("InputMapping").Delete(s).Error err = db.Model(&m).Association("InputMapping").Delete(s).Error

View file

@ -27,7 +27,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
) )
func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) { func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) {
@ -50,7 +50,7 @@ func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) {
return false, sig return false, sig
} }
ok, _ := simulationmodel.CheckPermissions(c, operation, "body", int(sig.SimulationModelID)) ok, _ := component_configuration.CheckPermissions(c, operation, "body", int(sig.ConfigID))
if !ok { if !ok {
return false, sig return false, sig
} }

View file

@ -26,9 +26,9 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration" "git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulator"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
@ -46,17 +46,17 @@ type SignalRequest struct {
Unit string `json:"unit,omitempty"` Unit string `json:"unit,omitempty"`
Index uint `json:"index,omitempty"` Index uint `json:"index,omitempty"`
Direction string `json:"direction,omitempty"` Direction string `json:"direction,omitempty"`
SimulationModelID uint `json:"simulationModelID,omitempty"` ConfigID uint `json:"configID,omitempty"`
} }
type SimulationModelRequest struct { type ConfigRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"` ScenarioID uint `json:"scenarioID,omitempty"`
SimulatorID uint `json:"simulatorID,omitempty"` ICID uint `json:"icID,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
} }
type SimulatorRequest struct { type ICRequest struct {
UUID string `json:"uuid,omitempty"` UUID string `json:"uuid,omitempty"`
Host string `json:"host,omitempty"` Host string `json:"host,omitempty"`
Modeltype string `json:"modelType,omitempty"` Modeltype string `json:"modelType,omitempty"`
@ -70,25 +70,25 @@ type ScenarioRequest struct {
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
} }
func addScenarioAndSimulatorAndSimulationModel() (scenarioID uint, simulatorID uint, simulationModelID uint) { func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
// authenticate as admin // authenticate as admin
token, _ := helper.AuthenticateForTest(router, token, _ := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.AdminCredentials) "/api/authenticate", "POST", helper.AdminCredentials)
// POST $newSimulatorA // POST $newICA
newSimulatorA := SimulatorRequest{ newICA := ICRequest{
UUID: database.SimulatorA.UUID, UUID: database.ICA.UUID,
Host: database.SimulatorA.Host, Host: database.ICA.Host,
Modeltype: database.SimulatorA.Modeltype, Modeltype: database.ICA.Modeltype,
State: database.SimulatorA.State, State: database.ICA.State,
Properties: database.SimulatorA.Properties, Properties: database.ICA.Properties,
} }
_, resp, _ := helper.TestEndpoint(router, token, _, resp, _ := helper.TestEndpoint(router, token,
"/api/simulators", "POST", helper.KeyModels{"simulator": newSimulatorA}) "/api/ic", "POST", helper.KeyModels{"ic": newICA})
// Read newSimulator's ID from the response // Read newIC's ID from the response
newSimulatorID, _ := helper.GetResponseID(resp) newICID, _ := helper.GetResponseID(resp)
// authenticate as normal user // authenticate as normal user
token, _ = helper.AuthenticateForTest(router, token, _ = helper.AuthenticateForTest(router,
@ -106,24 +106,24 @@ func addScenarioAndSimulatorAndSimulationModel() (scenarioID uint, simulatorID u
// Read newScenario's ID from the response // Read newScenario's ID from the response
newScenarioID, _ := helper.GetResponseID(resp) newScenarioID, _ := helper.GetResponseID(resp)
// test POST models/ $newSimulationModel // test POST newConfig
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: uint(newScenarioID), ScenarioID: uint(newScenarioID),
SimulatorID: uint(newSimulatorID), ICID: uint(newICID),
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
} }
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) "/api/configs", "POST", helper.KeyModels{"config": newConfig})
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, _ := helper.GetResponseID(resp) newConfigID, _ := helper.GetResponseID(resp)
// add the guest user to the new scenario // add the guest user to the new scenario
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil) fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
return uint(newScenarioID), uint(newSimulatorID), uint(newSimulationModelID) return uint(newScenarioID), uint(newICID), uint(newConfigID)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -143,15 +143,15 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
// simulationmodel endpoints required here to first add a simulation to the DB // component-configuration endpoints required here to first add a component config to the DB
// that can be associated with a new signal model // that can be associated with a new signal
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models")) component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// scenario endpoints required here to first add a scenario to the DB // scenario endpoints required here to first add a scenario to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
// simulator endpoints required here to first add a simulator to the DB // IC endpoints required here to first add a IC to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
simulator.RegisterSimulatorEndpoints(api.Group("/simulators")) infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
RegisterSignalEndpoints(api.Group("/signals")) RegisterSignalEndpoints(api.Group("/signals"))
os.Exit(m.Run()) os.Exit(m.Run())
@ -163,9 +163,9 @@ func TestAddSignal(t *testing.T) {
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndSimulatorAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -177,7 +177,7 @@ func TestAddSignal(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
// authenticate as normal userB who has no access to new scenario // authenticate as normal userB who has no access to new scenario
@ -185,7 +185,7 @@ func TestAddSignal(t *testing.T) {
"/api/authenticate", "POST", helper.UserBCredentials) "/api/authenticate", "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to POST to simulation model without access // try to POST to component config without access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal}) "/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -258,9 +258,9 @@ func TestUpdateSignal(t *testing.T) {
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndSimulatorAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -273,7 +273,7 @@ func TestUpdateSignal(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal}) "/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -360,9 +360,9 @@ func TestDeleteSignal(t *testing.T) {
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndSimulatorAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -375,7 +375,7 @@ func TestDeleteSignal(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal}) "/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -403,9 +403,9 @@ func TestDeleteSignal(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all the input signals returned for simulation model // Count the number of all the input signals returned for component config
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// add an output signal to make sure that counting of input signals works // add an output signal to make sure that counting of input signals works
@ -414,7 +414,7 @@ func TestDeleteSignal(t *testing.T) {
Unit: database.OutSignalA.Unit, Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction, Direction: database.OutSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalout}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalout})
@ -435,9 +435,9 @@ func TestDeleteSignal(t *testing.T) {
err = helper.CompareResponse(resp, helper.KeyModels{"signal": newSignal}) err = helper.CompareResponse(resp, helper.KeyModels{"signal": newSignal})
assert.NoError(t, err) assert.NoError(t, err)
// Again count the number of all the input signals returned for simulation model // Again count the number of all the input signals returned for component config
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber-1, finalNumber) assert.Equal(t, initialNumber-1, finalNumber)
@ -449,24 +449,24 @@ func TestDeleteSignal(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
} }
func TestGetAllInputSignalsOfSimulationModel(t *testing.T) { func TestGetAllInputSignalsOfConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a simulator to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndSimulatorAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all the input signals returned for simulation model // Count the number of all the input signals returned for component config
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// test POST signals/ $newSignal // test POST signals/ $newSignal
@ -475,7 +475,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalA}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalA})
@ -488,7 +488,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.InSignalB.Unit, Unit: database.InSignalB.Unit,
Direction: database.InSignalB.Direction, Direction: database.InSignalB.Direction,
Index: 2, Index: 2,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalB}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalB})
@ -501,7 +501,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.OutSignalA.Unit, Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction, Direction: database.OutSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalAout}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalAout})
@ -514,30 +514,30 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.OutSignalB.Unit, Unit: database.OutSignalB.Unit,
Direction: database.OutSignalB.Direction, Direction: database.OutSignalB.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalBout}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalBout})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Again count the number of all the input signals returned for simulation model // Again count the number of all the input signals returned for component config
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber+2, finalNumber) assert.Equal(t, initialNumber+2, finalNumber)
// Get the number of output signals // Get the number of output signals
outputNumber, err := helper.LengthOfResponse(router, token, outputNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=out", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=out", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber+2, outputNumber) assert.Equal(t, initialNumber+2, outputNumber)
// Try to get all signals for non-existing direction // Try to get all signals for non-existing direction
// should result in bad request // should result in bad request
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=thisiswrong", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=thisiswrong", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp) assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
@ -549,7 +549,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
// try to get all input signals // try to get all input signals
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)

View file

@ -32,7 +32,7 @@ type validNewSignal struct {
Unit string `form:"unit" validate:"omitempty"` Unit string `form:"unit" validate:"omitempty"`
Index uint `form:"index" validate:"required"` Index uint `form:"index" validate:"required"`
Direction string `form:"direction" validate:"required,oneof=in out"` Direction string `form:"direction" validate:"required,oneof=in out"`
SimulationModelID uint `form:"simulationModelID" validate:"required"` ConfigID uint `form:"configID" validate:"required"`
} }
type validUpdatedSignal struct { type validUpdatedSignal struct {
@ -68,7 +68,7 @@ func (r *addSignalRequest) createSignal() Signal {
s.Unit = r.Signal.Unit s.Unit = r.Signal.Unit
s.Index = r.Signal.Index s.Index = r.Signal.Index
s.Direction = r.Signal.Direction s.Direction = r.Signal.Direction
s.SimulationModelID = r.Signal.SimulationModelID s.ConfigID = r.Signal.ConfigID
return s return s
} }

View file

@ -1,108 +0,0 @@
/** Simulationmodel package, validators.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
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"`
SelectedModelFileID uint `form:"SelectedModelFilID" validate:"omitempty"`
}
type validUpdatedSimulationModel struct {
Name string `form:"Name" validate:"omitempty"`
SimulatorID uint `form:"SimulatorID" validate:"omitempty"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"omitempty"`
SelectedModelFileID uint `form:"SelectedModelFileID" validate:"omitempty"`
}
type addSimulationModelRequest struct {
SimulationModel validNewSimulationModel `json:"simulationModel"`
}
type updateSimulationModelRequest struct {
SimulationModel validUpdatedSimulationModel `json:"simulationModel"`
}
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.SimulationModel.Name
s.ScenarioID = r.SimulationModel.ScenarioID
s.SimulatorID = r.SimulationModel.SimulatorID
s.StartParameters = r.SimulationModel.StartParameters
s.SelectedModelFileID = r.SimulationModel.SelectedModelFileID
return s
}
func (r *updateSimulationModelRequest) updatedSimulationModel(oldSimulationModel SimulationModel) SimulationModel {
// Use the old SimulationModel as a basis for the updated Simulation model
s := oldSimulationModel
if r.SimulationModel.Name != "" {
s.Name = r.SimulationModel.Name
}
if r.SimulationModel.SimulatorID != 0 {
s.SimulatorID = r.SimulationModel.SimulatorID
}
if r.SimulationModel.SelectedModelFileID != 0 {
s.SelectedModelFileID = r.SimulationModel.SelectedModelFileID
}
// 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.SimulationModel.StartParameters)
opts := jsondiff.DefaultConsoleOptions()
diff, _ := jsondiff.Compare(emptyJson_ser, startParams_ser, &opts)
if diff.String() != "FullMatch" {
s.StartParameters = r.SimulationModel.StartParameters
}
return s
}

View file

@ -289,7 +289,7 @@ func TestUpdateWidget(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user who has access to simulation model // authenticate as guest user who has access to scenario
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.GuestCredentials) "/api/authenticate", "POST", helper.GuestCredentials)
assert.NoError(t, err) assert.NoError(t, err)

View file

@ -34,13 +34,13 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration" "git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
apidocs "git.rwth-aachen.de/acs/public/villas/web-backend-go/doc/api" // doc/api folder is used by Swag CLI, you have to import it apidocs "git.rwth-aachen.de/acs/public/villas/web-backend-go/doc/api" // doc/api folder is used by Swag CLI, you have to import it
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/metrics" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/metrics"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/signal" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/signal"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulator"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
) )
@ -114,13 +114,13 @@ func main() {
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models")) component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
signal.RegisterSignalEndpoints(api.Group("/signals")) signal.RegisterSignalEndpoints(api.Group("/signals"))
dashboard.RegisterDashboardEndpoints(api.Group("/dashboards")) dashboard.RegisterDashboardEndpoints(api.Group("/dashboards"))
widget.RegisterWidgetEndpoints(api.Group("/widgets")) widget.RegisterWidgetEndpoints(api.Group("/widgets"))
file.RegisterFileEndpoints(api.Group("/files")) file.RegisterFileEndpoints(api.Group("/files"))
user.RegisterUserEndpoints(api.Group("/users")) user.RegisterUserEndpoints(api.Group("/users"))
simulator.RegisterSimulatorEndpoints(api.Group("/simulators")) infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
r.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) r.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
@ -133,10 +133,10 @@ func main() {
log.Panic(err) log.Panic(err)
} }
// register simulator action endpoint only if AMQP client is used // register IC action endpoint only if AMQP client is used
amqp.RegisterAMQPEndpoint(api.Group("/simulators")) amqp.RegisterAMQPEndpoint(api.Group("/ic"))
// Periodically call the Ping function to check which simulators are still there // Periodically call the Ping function to check which ICs are still there
ticker := time.NewTicker(10 * time.Second) ticker := time.NewTicker(10 * time.Second)
go func() { go func() {