renaming: simulation model = component configuration

This commit is contained in:
Sonja Happ 2020-03-06 15:14:29 +01:00
parent 5d63fc3e26
commit ef1dede70c
32 changed files with 1948 additions and 1943 deletions

View file

@ -95,10 +95,10 @@ test:scenario:
variables:
TEST_FOLDER: routes/scenario
test:simulationmodel:
extends: test:scenario
test:component-configuration:
extends: test:database
variables:
TEST_FOLDER: routes/simulationmodel
TEST_FOLDER: routes/component-configuration
test:signal:
extends: test:database

View file

@ -104,7 +104,7 @@ func GetDB() *gorm.DB {
func DropTables(db *gorm.DB) {
db.DropTableIfExists(&InfrastructureComponent{})
db.DropTableIfExists(&Signal{})
db.DropTableIfExists(&SimulationModel{})
db.DropTableIfExists(&ComponentConfiguration{})
db.DropTableIfExists(&File{})
db.DropTableIfExists(&Scenario{})
db.DropTableIfExists(&User{})
@ -118,7 +118,7 @@ func DropTables(db *gorm.DB) {
func MigrateModels(db *gorm.DB) {
db.AutoMigrate(&InfrastructureComponent{})
db.AutoMigrate(&Signal{})
db.AutoMigrate(&SimulationModel{})
db.AutoMigrate(&ComponentConfiguration{})
db.AutoMigrate(&File{})
db.AutoMigrate(&Scenario{})
db.AutoMigrate(&User{})

View file

@ -107,8 +107,8 @@ func TestScenarioAssociations(t *testing.T) {
user0 := User0
userA := UserA
userB := UserB
modelA := SimulationModelA
modelB := SimulationModelB
configA := ConfigA
configB := ConfigB
dashboardA := DashboardA
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(&userB).Error) // Normal User
// add simulation models to DB
assert.NoError(t, db.Create(&modelA).Error)
assert.NoError(t, db.Create(&modelB).Error)
// add component configurations to DB
assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&configB).Error)
// add dashboards to DB
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(&userB).Error)
// add scenario has many simulation models associations
assert.NoError(t, db.Model(&scenarioA).Association("SimulationModels").Append(&modelA).Error)
assert.NoError(t, db.Model(&scenarioA).Association("SimulationModels").Append(&modelB).Error)
// add scenario has many component configurations associations
assert.NoError(t, db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configB).Error)
// Scenario HM Dashboards
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))
}
// Get simulation models of scenario1
var models []SimulationModel
assert.NoError(t, db.Model(&scenario1).Related(&models, "SimulationModels").Error)
if len(models) != 2 {
// Get component configurations of scenario1
var configs []ComponentConfiguration
assert.NoError(t, db.Model(&scenario1).Related(&configs, "ComponentConfigurations").Error)
if len(configs) != 2 {
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
@ -181,42 +181,42 @@ func TestICAssociations(t *testing.T) {
// create copies of global test data
icA := ICA
icB := ICB
modelA := SimulationModelA
modelB := SimulationModelB
configA := ConfigA
configB := ConfigB
// add ICs to DB
assert.NoError(t, db.Create(&icA).Error)
assert.NoError(t, db.Create(&icB).Error)
// add simulation models to DB
assert.NoError(t, db.Create(&modelA).Error)
assert.NoError(t, db.Create(&modelB).Error)
// add component configurations to DB
assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&configB).Error)
// add IC has many simulation models association to DB
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelA).Error)
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelB).Error)
// add IC has many component configurations association to DB
assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
var ic1 InfrastructureComponent
assert.NoError(t, db.Find(&ic1, 1).Error, fmt.Sprintf("Find InfrastructureComponent with ID=1"))
assert.EqualValues(t, "Host_A", ic1.Host)
// Get simulation models of ic1
var models []SimulationModel
assert.NoError(t, db.Model(&ic1).Association("SimulationModels").Find(&models).Error)
if len(models) != 2 {
// Get Component Configurations of ic1
var configs []ComponentConfiguration
assert.NoError(t, db.Model(&ic1).Association("ComponentConfigurations").Find(&configs).Error)
if len(configs) != 2 {
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)
MigrateModels(db)
// create copies of global test data
modelA := SimulationModelA
modelB := SimulationModelB
configA := ConfigA
configB := ConfigB
outSignalA := OutSignalA
outSignalB := OutSignalB
inSignalA := InSignalA
@ -228,9 +228,9 @@ func TestSimulationModelAssociations(t *testing.T) {
icA := ICA
icB := ICB
// add simulation models to DB
assert.NoError(t, db.Create(&modelA).Error)
assert.NoError(t, db.Create(&modelB).Error)
// add Component Configurations to DB
assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&configB).Error)
// add signals to DB
assert.NoError(t, db.Create(&outSignalA).Error)
@ -248,42 +248,42 @@ func TestSimulationModelAssociations(t *testing.T) {
assert.NoError(t, db.Create(&icA).Error)
assert.NoError(t, db.Create(&icB).Error)
// add simulation model has many signals associations
assert.NoError(t, db.Model(&modelA).Association("InputMapping").Append(&inSignalA).Error)
assert.NoError(t, db.Model(&modelA).Association("InputMapping").Append(&inSignalB).Error)
assert.NoError(t, db.Model(&modelA).Association("OutputMapping").Append(&outSignalA).Error)
assert.NoError(t, db.Model(&modelA).Association("OutputMapping").Append(&outSignalB).Error)
// add Component Configuration has many signals associations
assert.NoError(t, db.Model(&configA).Association("InputMapping").Append(&inSignalA).Error)
assert.NoError(t, db.Model(&configA).Association("InputMapping").Append(&inSignalB).Error)
assert.NoError(t, db.Model(&configA).Association("OutputMapping").Append(&outSignalA).Error)
assert.NoError(t, db.Model(&configA).Association("OutputMapping").Append(&outSignalB).Error)
// add simulation model has many files associations
assert.NoError(t, db.Model(&modelA).Association("Files").Append(&fileC).Error)
assert.NoError(t, db.Model(&modelA).Association("Files").Append(&fileD).Error)
// add Component Configuration has many files associations
assert.NoError(t, db.Model(&configA).Association("Files").Append(&fileC).Error)
assert.NoError(t, db.Model(&configA).Association("Files").Append(&fileD).Error)
// associate simulation models with IC
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelA).Error)
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelB).Error)
// associate Component Configurations with IC
assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
var model1 SimulationModel
assert.NoError(t, db.Find(&model1, 1).Error, fmt.Sprintf("Find SimulationModel with ID=1"))
assert.EqualValues(t, "SimulationModel_A", model1.Name)
var config1 ComponentConfiguration
assert.NoError(t, db.Find(&config1, 1).Error, fmt.Sprintf("Find ComponentConfiguration with ID=1"))
assert.EqualValues(t, ConfigA.Name, config1.Name)
// Check IC ID
if model1.ICID != 1 {
assert.Fail(t, "Simulation Model expected to have InfrastructureComponent ID 1, but is %v", model1.ICID)
if config1.ICID != 1 {
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
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 {
assert.Fail(t, "SimulationModel Associations",
assert.Fail(t, "ComponentConfiguration Associations",
"Expected to have %v Output Signals. Has %v.", 2, len(signals))
}
// Get files of model1
// Get files of config1
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 {
assert.Fail(t, "SimulationModel Associations",
assert.Fail(t, "ComponentConfiguration Associations",
"Expected to have %v Files. Has %v.", 2, len(files))
}
}

View file

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

View file

@ -42,7 +42,7 @@ const ModelInfrastructureComponent = ModelName("ic")
const ModelInfrastructureComponentAction = ModelName("icaction")
const ModelDashboard = ModelName("dashboard")
const ModelWidget = ModelName("widget")
const ModelSimulationModel = ModelName("simulationmodel")
const ModelComponentConfiguration = ModelName("component-configuration")
const ModelSignal = ModelName("signal")
const ModelFile = ModelName("file")
@ -76,7 +76,7 @@ var Roles = RoleActions{
ModelUser: crud,
ModelUsers: crud,
ModelScenario: crud,
ModelSimulationModel: crud,
ModelComponentConfiguration: crud,
ModelInfrastructureComponent: crud,
ModelInfrastructureComponentAction: crud,
ModelWidget: crud,
@ -88,7 +88,7 @@ var Roles = RoleActions{
ModelUser: _ru_,
ModelUsers: none,
ModelScenario: crud,
ModelSimulationModel: crud,
ModelComponentConfiguration: crud,
ModelInfrastructureComponent: _r__,
ModelInfrastructureComponentAction: _ru_,
ModelWidget: crud,
@ -98,7 +98,7 @@ var Roles = RoleActions{
},
"Guest": {
ModelScenario: _r__,
ModelSimulationModel: _r__,
ModelComponentConfiguration: _r__,
ModelDashboard: _r__,
ModelWidget: _r__,
ModelInfrastructureComponent: _r__,

View file

@ -98,18 +98,18 @@ var ScenarioB = Scenario{
StartParameters: postgres.Jsonb{startParametersB},
}
// Simulation Models
// Component Configuration
var SimulationModelA = SimulationModel{
Name: "SimulationModel_A",
var ConfigA = ComponentConfiguration{
Name: "Example simulation",
StartParameters: postgres.Jsonb{startParametersA},
SelectedModelFileID: 3,
SelectedFileID: 3,
}
var SimulationModelB = SimulationModel{
Name: "SimulationModel_B",
var ConfigB = ComponentConfiguration{
Name: "VILLASnode gateway X",
StartParameters: postgres.Jsonb{startParametersB},
SelectedModelFileID: 4,
SelectedFileID: 4,
}
// 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 customPropertiesCustomActions = json.RawMessage(`{"actions" : "Value1", "icon" : "Value2"}`)
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{
Name: "Label",
@ -327,8 +327,8 @@ func DBAddTestData(db *gorm.DB) error {
inSignalA := InSignalA
inSignalB := InSignalB
modelA := SimulationModelA
modelB := SimulationModelB
configA := ConfigA
configB := ConfigB
dashboardA := DashboardA
dashboardB := DashboardB
@ -368,9 +368,9 @@ func DBAddTestData(db *gorm.DB) error {
err = db.Create(&outSignalA).Error
err = db.Create(&outSignalB).Error
// Simulation Models
err = db.Create(&modelA).Error
err = db.Create(&modelB).Error
// Component Configuration
err = db.Create(&configA).Error
err = db.Create(&configB).Error
// Dashboards
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(&user0).Error
// Scenario HM SimulationModels
err = db.Model(&scenarioA).Association("SimulationModels").Append(&modelA).Error
err = db.Model(&scenarioA).Association("SimulationModels").Append(&modelB).Error
// Scenario HM Component Configurations
err = db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configA).Error
err = db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configB).Error
// Scenario HM Dashboards
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(&widgetE).Error
// SimulationModel HM Signals
err = db.Model(&modelA).Association("InputMapping").Append(&inSignalA).Error
err = db.Model(&modelA).Association("InputMapping").Append(&inSignalB).Error
err = db.Model(&modelA).Association("InputMapping").Append(&outSignalA).Error
err = db.Model(&modelA).Association("InputMapping").Append(&outSignalB).Error
// ComponentConfiguration HM Signals
err = db.Model(&configA).Association("InputMapping").Append(&inSignalA).Error
err = db.Model(&configA).Association("InputMapping").Append(&inSignalB).Error
err = db.Model(&configA).Association("InputMapping").Append(&outSignalA).Error
err = db.Model(&configA).Association("InputMapping").Append(&outSignalB).Error
// SimulationModel HM Files
err = db.Model(&modelA).Association("Files").Append(&fileC).Error
err = db.Model(&modelA).Association("Files").Append(&fileD).Error
// ComponentConfiguration HM Files
err = db.Model(&configA).Association("Files").Append(&fileC).Error
err = db.Model(&configA).Association("Files").Append(&fileD).Error
// InfrastructureComponent HM SimulationModels
err = db.Model(&ICA).Association("SimulationModels").Append(&modelA).Error
err = db.Model(&ICA).Association("SimulationModels").Append(&modelB).Error
// InfrastructureComponent HM ComponentConfigurations
err = db.Model(&ICA).Association("ComponentConfigurations").Append(&configA).Error
err = db.Model(&ICA).Association("ComponentConfigurations").Append(&configB).Error
// Widget HM Files
err = db.Model(&widgetA).Association("Files").Append(&fileA).Error

File diff suppressed because it is too large Load diff

View file

@ -62,12 +62,12 @@ type ResponseScenario struct {
scenario database.Scenario
}
type ResponseSimulationModels struct {
simulationModels []database.SimulationModel
type ResponseConfigs struct {
configs []database.ComponentConfiguration
}
type ResponseSimulationModel struct {
simulationModel database.SimulationModel
type ResponseConfig struct {
config database.ComponentConfiguration
}
type ResponseDashboards struct {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,46 @@
basePath: /api/v2
definitions:
component_configuration.addConfigRequest:
properties:
config:
$ref: '#/definitions/component_configuration.validNewConfig'
type: object
type: object
component_configuration.updateConfigRequest:
properties:
config:
$ref: '#/definitions/component_configuration.validUpdatedConfig'
type: object
type: object
component_configuration.validNewConfig:
properties:
ICID:
type: integer
Name:
type: string
ScenarioID:
type: integer
SelectedFileID:
type: integer
StartParameters:
type: string
required:
- ICID
- Name
- ScenarioID
- StartParameters
type: object
component_configuration.validUpdatedConfig:
properties:
ICID:
type: integer
Name:
type: string
SelectedFileID:
type: integer
StartParameters:
type: string
type: object
dashboard.addDashboardRequest:
properties:
dashboard:
@ -32,6 +73,32 @@ definitions:
name:
type: string
type: object
database.ComponentConfiguration:
properties:
icID:
description: ID of IC associated with Component Configuration
type: integer
id:
type: integer
inputLength:
description: Number of input signals
type: integer
name:
description: Name of Component Configuration
type: string
outputLength:
description: Number of output signals
type: integer
scenarioID:
description: ID of Scenario to which Component Configuration belongs
type: integer
selectedFileID:
description: Currently selected FileID
type: integer
startParameters:
description: Start parameters of Component Configuration as JSON
type: string
type: object
database.Dashboard:
properties:
grid:
@ -48,6 +115,9 @@ definitions:
type: object
database.File:
properties:
configID:
description: ID of Component Configuration to which file belongs
type: integer
date:
description: Last modification time of file
type: string
@ -62,9 +132,6 @@ definitions:
name:
description: Name of file
type: string
simulationModelID:
description: ID of model to which file belongs
type: integer
size:
description: Size of file (in byte)
type: integer
@ -120,6 +187,9 @@ definitions:
type: object
database.Signal:
properties:
configID:
description: ID of Component Configuration
type: integer
direction:
description: Direction of the signal (in or out)
type: string
@ -131,39 +201,10 @@ definitions:
name:
description: Name of Signal
type: string
simulationModelID:
description: ID of simulation model
type: integer
unit:
description: Unit of Signal
type: string
type: object
database.SimulationModel:
properties:
icID:
description: ID of IC associated with simulation model
type: integer
id:
type: integer
inputLength:
description: Number of input signals
type: integer
name:
description: Name of simulation model
type: string
outputLength:
description: Number of output signals
type: integer
scenarioID:
description: ID of Scenario to which simulation model belongs
type: integer
selectedModelFileID:
description: Currently selected simulation model FileID
type: integer
startParameters:
description: Start parameters of simulation model as JSON
type: string
type: object
database.User:
properties:
active:
@ -238,6 +279,19 @@ definitions:
$ref: '#/definitions/database.User'
type: object
type: object
docs.ResponseConfig:
properties:
config:
$ref: '#/definitions/database.ComponentConfiguration'
type: object
type: object
docs.ResponseConfigs:
properties:
configs:
items:
$ref: '#/definitions/database.ComponentConfiguration'
type: array
type: object
docs.ResponseDashboard:
properties:
dashboard:
@ -310,19 +364,6 @@ definitions:
$ref: '#/definitions/database.Signal'
type: array
type: object
docs.ResponseSimulationModel:
properties:
simulationModel:
$ref: '#/definitions/database.SimulationModel'
type: object
type: object
docs.ResponseSimulationModels:
properties:
simulationModels:
items:
$ref: '#/definitions/database.SimulationModel'
type: array
type: object
docs.ResponseUser:
properties:
user:
@ -439,21 +480,21 @@ definitions:
type: object
signal.validNewSignal:
properties:
ConfigID:
type: integer
Direction:
type: string
Index:
type: integer
Name:
type: string
SimulationModelID:
type: integer
Unit:
type: string
required:
- ConfigID
- Direction
- Index
- Name
- SimulationModelID
type: object
signal.validUpdatedSignal:
properties:
@ -464,47 +505,6 @@ definitions:
Unit:
type: string
type: object
simulationmodel.addSimulationModelRequest:
properties:
simulationModel:
$ref: '#/definitions/simulationmodel.validNewSimulationModel'
type: object
type: object
simulationmodel.updateSimulationModelRequest:
properties:
simulationModel:
$ref: '#/definitions/simulationmodel.validUpdatedSimulationModel'
type: object
type: object
simulationmodel.validNewSimulationModel:
properties:
ICID:
type: integer
Name:
type: string
ScenarioID:
type: integer
SelectedModelFileID:
type: integer
StartParameters:
type: string
required:
- ICID
- Name
- ScenarioID
- StartParameters
type: object
simulationmodel.validUpdatedSimulationModel:
properties:
ICID:
type: integer
Name:
type: string
SelectedModelFileID:
type: integer
StartParameters:
type: string
type: object
user.addUserRequest:
properties:
user:
@ -686,6 +686,237 @@ paths:
summary: Authentication for user
tags:
- authentication
/configs:
get:
operationId: getConfigs
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Scenario ID
in: query
name: scenarioID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: Component configurations which belong to scenario
schema:
$ref: '#/definitions/docs.ResponseConfigs'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get all component configurations of scenario
tags:
- component-configurations
post:
consumes:
- application/json
operationId: addConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: component configuration to be added incl. IDs of scenario and
IC
in: body
name: inputConfig
required: true
schema:
$ref: '#/definitions/component_configuration.addConfigRequest'
type: object
produces:
- application/json
responses:
"200":
description: Component configuration that was added
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Add a component configuration to a scenario
tags:
- component-configurations
/configs/{configID}:
delete:
operationId: deleteConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Config ID
in: path
name: configID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: component configuration that was deleted
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Delete a component configuration
tags:
- component-configurations
get:
operationId: getConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Config ID
in: path
name: configID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: component configuration that was requested
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get a component configuration
tags:
- component-configurations
put:
consumes:
- application/json
operationId: updateConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: component configuration to be updated
in: body
name: inputConfig
required: true
schema:
$ref: '#/definitions/component_configuration.updateConfigRequest'
type: object
- description: Config ID
in: path
name: configID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: Component configuration that was added
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Update a component configuration
tags:
- component-configurations
/dashboards:
get:
operationId: getDashboards
@ -925,12 +1156,13 @@ paths:
name: Authorization
required: true
type: string
- description: Set to model for files of model, set to widget for files of widget
- description: Set to config for files of component configuration, set to widget
for files of widget
in: query
name: objectType
required: true
type: string
- description: ID of either model or widget of which files are requested
- description: ID of either config or widget of which files are requested
in: query
name: objectID
required: true
@ -939,7 +1171,7 @@ paths:
- application/json
responses:
"200":
description: Files which belong to simulation model or widget
description: Files which belong to config or widget
schema:
$ref: '#/definitions/docs.ResponseFiles'
type: object
@ -958,7 +1190,7 @@ paths:
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get all files of a specific model or widget
summary: Get all files of a specific component configuration or widget
tags:
- files
post:
@ -981,12 +1213,13 @@ paths:
name: inputFile
required: true
type: file
- description: Set to model for files of model, set to widget for files of widget
- description: Set to config for files of component config, set to widget for
files of widget
in: query
name: objectType
required: true
type: string
- description: ID of either model or widget of which files are requested
- description: ID of either config or widget of which files are requested
in: query
name: objectID
required: true
@ -1019,7 +1252,7 @@ paths:
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Add a file to a specific model or widget
summary: Add a file to a specific component config or widget
tags:
- files
/files/{fileID}:
@ -1480,7 +1713,7 @@ paths:
"200":
description: Configs requested by user
schema:
$ref: '#/definitions/docs.ResponseSimulationModels'
$ref: '#/definitions/docs.ResponseConfigs'
type: object
"400":
description: Bad request
@ -1516,236 +1749,6 @@ paths:
summary: Prometheus metrics endpoint
tags:
- metrics
/models:
get:
operationId: getSimulationModels
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Scenario ID
in: query
name: scenarioID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: Simulation models which belong to scenario
schema:
$ref: '#/definitions/docs.ResponseSimulationModels'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get all simulation models of scenario
tags:
- simulationModels
post:
consumes:
- application/json
operationId: addSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Simulation model to be added incl. IDs of scenario and IC
in: body
name: inputSimulationModel
required: true
schema:
$ref: '#/definitions/simulationmodel.addSimulationModelRequest'
type: object
produces:
- application/json
responses:
"200":
description: simulation model that was added
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Add a simulation model to a scenario
tags:
- simulationModels
/models/{modelID}:
delete:
operationId: deleteSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Model ID
in: path
name: modelID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: simulation model that was deleted
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Delete a simulation model
tags:
- simulationModels
get:
operationId: getSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Model ID
in: path
name: modelID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: simulation model that was requested
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get a simulation model
tags:
- simulationModels
put:
consumes:
- application/json
operationId: updateSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Simulation model to be updated
in: body
name: inputSimulationModel
required: true
schema:
$ref: '#/definitions/simulationmodel.updateSimulationModelRequest'
type: object
- description: Model ID
in: path
name: modelID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: simulation model that was added
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Update a simulation model
tags:
- simulationModels
/scenarios:
get:
operationId: getScenarios
@ -2099,9 +2102,9 @@ paths:
name: direction
required: true
type: string
- description: Model ID of signals to be obtained
- description: Config ID of signals to be obtained
in: query
name: modelID
name: configID
required: true
type: string
- description: Authorization token
@ -2113,7 +2116,7 @@ paths:
- application/json
responses:
"200":
description: Signals which belong to simulation model
description: Signals which belong to component configuration
schema:
$ref: '#/definitions/docs.ResponseSignals'
type: object
@ -2145,8 +2148,8 @@ paths:
name: Authorization
required: true
type: string
- description: A signal to be added to the model incl. direction and model ID
to which signal shall be added
- description: A signal to be added to the component configuration incl. direction
and config ID to which signal shall be added
in: body
name: inputSignal
required: true
@ -2181,7 +2184,7 @@ paths:
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Add a signal to a signal mapping of a model
summary: Add a signal to a signal mapping of a component configuration
tags:
- signals
/signals/{signalID}:

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, endpoints.
/** component_configuration package, endpoints.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package simulationmodel
package component_configuration
import (
"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"
)
func RegisterSimulationModelEndpoints(r *gin.RouterGroup) {
r.GET("", getSimulationModels)
r.POST("", addSimulationModel)
r.PUT("/:modelID", updateSimulationModel)
r.GET("/:modelID", getSimulationModel)
r.DELETE("/:modelID", deleteSimulationModel)
func RegisterComponentConfigurationEndpoints(r *gin.RouterGroup) {
r.GET("", getConfigs)
r.POST("", addConfig)
r.PUT("/:configID", updateConfig)
r.GET("/:configID", getConfig)
r.DELETE("/:configID", deleteConfig)
}
// getSimulationModels godoc
// @Summary Get all simulation models of scenario
// @ID getSimulationModels
// getConfigs godoc
// @Summary Get all component configurations of scenario
// @ID getConfigs
// @Produce json
// @Tags simulationModels
// @Success 200 {object} docs.ResponseSimulationModels "Simulation models which belong to scenario"
// @Tags component-configurations
// @Success 200 {object} docs.ResponseConfigs "Component configurations which belong to scenario"
// @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token"
// @Param scenarioID query int true "Scenario ID"
// @Router /models [get]
func getSimulationModels(c *gin.Context) {
// @Router /configs [get]
func getConfigs(c *gin.Context) {
ok, so := scenario.CheckPermissions(c, database.Read, "query", -1)
if !ok {
@ -59,32 +59,32 @@ func getSimulationModels(c *gin.Context) {
}
db := database.GetDB()
var models []database.SimulationModel
err := db.Order("ID asc").Model(so).Related(&models, "Models").Error
var configs []database.ComponentConfiguration
err := db.Order("ID asc").Model(so).Related(&configs, "ComponentConfigurations").Error
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModels": models})
c.JSON(http.StatusOK, gin.H{"configs": configs})
}
}
// addSimulationModel godoc
// @Summary Add a simulation model to a scenario
// @ID addSimulationModel
// addConfig godoc
// @Summary Add a component configuration to a scenario
// @ID addConfig
// @Accept json
// @Produce json
// @Tags simulationModels
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was added"
// @Tags component-configurations
// @Success 200 {object} docs.ResponseConfig "Component configuration that was added"
// @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token"
// @Param inputSimulationModel body simulationmodel.addSimulationModelRequest true "Simulation model to be added incl. IDs of scenario and IC"
// @Router /models [post]
func addSimulationModel(c *gin.Context) {
// @Param inputConfig body component_configuration.addConfigRequest true "component configuration to be added incl. IDs of scenario and IC"
// @Router /configs [post]
func addConfig(c *gin.Context) {
// Bind the request to JSON
var req addSimulationModelRequest
var req addConfigRequest
err := c.ShouldBindJSON(&req)
if err != nil {
helper.BadRequestError(c, "Bad request. Error binding form data to JSON: "+err.Error())
@ -97,46 +97,46 @@ func addSimulationModel(c *gin.Context) {
return
}
// Create the new simulation model from the request
newSimulationModel := req.createSimulationModel()
// Create the new Component Configuration from the request
newConfig := req.createConfig()
// 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 {
return
}
// add the new simulation model to the scenario
err = newSimulationModel.addToScenario()
// add the new Component Configuration to the scenario
err = newConfig.addToScenario()
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
// @Summary Update a simulation model
// @ID updateSimulationModel
// @Tags simulationModels
// updateConfig godoc
// @Summary Update a component configuration
// @ID updateConfig
// @Tags component-configurations
// @Accept 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 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token"
// @Param inputSimulationModel body simulationmodel.updateSimulationModelRequest true "Simulation model to be updated"
// @Param modelID path int true "Model ID"
// @Router /models/{modelID} [put]
func updateSimulationModel(c *gin.Context) {
// @Param inputConfig body component_configuration.updateConfigRequest true "component configuration to be updated"
// @Param configID path int true "Config ID"
// @Router /configs/{configID} [put]
func updateConfig(c *gin.Context) {
ok, oldSimulationModel := CheckPermissions(c, database.Update, "path", -1)
ok, oldConfig := CheckPermissions(c, database.Update, "path", -1)
if !ok {
return
}
var req updateSimulationModelRequest
var req updateConfigRequest
err := c.BindJSON(&req)
if err != nil {
helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error())
@ -144,59 +144,59 @@ func updateSimulationModel(c *gin.Context) {
}
// Validate the request
if err := req.SimulationModel.validate(); err != nil {
if err := req.Config.validate(); err != nil {
helper.BadRequestError(c, err.Error())
return
}
// Create the updatedSimulationModel from oldSimulationModel
updatedSimulationModel := req.updatedSimulationModel(oldSimulationModel)
// Create the updateConfig from oldConfig
updatedConfig := req.updateConfig(oldConfig)
// Finally, update the simulation model
err = oldSimulationModel.Update(updatedSimulationModel)
// Finally, update the Component Configuration
err = oldConfig.Update(updatedConfig)
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
// @Summary Get a simulation model
// @ID getSimulationModel
// @Tags simulationModels
// getConfig godoc
// @Summary Get a component configuration
// @ID getConfig
// @Tags component-configurations
// @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 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token"
// @Param modelID path int true "Model ID"
// @Router /models/{modelID} [get]
func getSimulationModel(c *gin.Context) {
// @Param configID path int true "Config ID"
// @Router /configs/{configID} [get]
func getConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Read, "path", -1)
if !ok {
return
}
c.JSON(http.StatusOK, gin.H{"simulationModel": m.SimulationModel})
c.JSON(http.StatusOK, gin.H{"config": m.ComponentConfiguration})
}
// deleteSimulationModel godoc
// @Summary Delete a simulation model
// @ID deleteSimulationModel
// @Tags simulationModels
// deleteConfig godoc
// @Summary Delete a component configuration
// @ID deleteConfig
// @Tags component-configurations
// @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 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token"
// @Param modelID path int true "Model ID"
// @Router /models/{modelID} [delete]
func deleteSimulationModel(c *gin.Context) {
// @Param configID path int true "Config ID"
// @Router /configs/{configID} [delete]
func deleteConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Delete, "path", -1)
if !ok {
@ -205,6 +205,6 @@ func deleteSimulationModel(c *gin.Context) {
err := m.delete()
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>
* @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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package simulationmodel
package component_configuration
import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
@ -27,17 +27,17 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
)
type SimulationModel struct {
database.SimulationModel
type ComponentConfiguration struct {
database.ComponentConfiguration
}
func (m *SimulationModel) save() error {
func (m *ComponentConfiguration) save() error {
db := database.GetDB()
err := db.Create(m).Error
return err
}
func (m *SimulationModel) ByID(id uint) error {
func (m *ComponentConfiguration) ByID(id uint) error {
db := database.GetDB()
err := db.Find(m, id).Error
if err != nil {
@ -46,7 +46,7 @@ func (m *SimulationModel) ByID(id uint) error {
return nil
}
func (m *SimulationModel) addToScenario() error {
func (m *ComponentConfiguration) addToScenario() error {
db := database.GetDB()
var so scenario.Scenario
err := so.ByID(m.ScenarioID)
@ -54,35 +54,35 @@ func (m *SimulationModel) addToScenario() error {
return err
}
// save simulation model to DB
// save component configuration to DB
err = m.save()
if err != nil {
return err
}
// associate IC with simulation model
// associate IC with component configuration
var ic infrastructure_component.InfrastructureComponent
err = ic.ByID(m.ICID)
err = db.Model(&ic).Association("SimulationModels").Append(m).Error
err = db.Model(&ic).Association("ComponentConfigurations").Append(m).Error
if err != nil {
return err
}
// associate simulation model with scenario
err = db.Model(&so).Association("SimulationModels").Append(m).Error
// associate component configuration with scenario
err = db.Model(&so).Association("ComponentConfigurations").Append(m).Error
return err
}
func (m *SimulationModel) Update(modifiedSimulationModel SimulationModel) error {
func (m *ComponentConfiguration) Update(modifiedConfig ComponentConfiguration) error {
db := database.GetDB()
// check if IC has been updated
if m.ICID != modifiedSimulationModel.ICID {
if m.ICID != modifiedConfig.ICID {
// update IC
var s infrastructure_component.InfrastructureComponent
var s_old infrastructure_component.InfrastructureComponent
err := s.ByID(modifiedSimulationModel.ICID)
err := s.ByID(modifiedConfig.ICID)
if err != nil {
return err
}
@ -90,29 +90,29 @@ func (m *SimulationModel) Update(modifiedSimulationModel SimulationModel) error
if err != nil {
return err
}
// remove simulation model from old IC
err = db.Model(&s_old).Association("SimulationModels").Delete(m).Error
// remove component configuration from old IC
err = db.Model(&s_old).Association("ComponentConfigurations").Delete(m).Error
if err != nil {
return err
}
// add simulation model to new IC
err = db.Model(&s).Association("SimulationModels").Append(m).Error
// add component configuration to new IC
err = db.Model(&s).Association("ComponentConfigurations").Append(m).Error
if err != nil {
return err
}
}
err := db.Model(m).Updates(map[string]interface{}{
"Name": modifiedSimulationModel.Name,
"StartParameters": modifiedSimulationModel.StartParameters,
"ICID": modifiedSimulationModel.ICID,
"SelectedModelFileID": modifiedSimulationModel.SelectedModelFileID,
"Name": modifiedConfig.Name,
"StartParameters": modifiedConfig.StartParameters,
"ICID": modifiedConfig.ICID,
"SelectedFileID": modifiedConfig.SelectedFileID,
}).Error
return err
}
func (m *SimulationModel) delete() error {
func (m *ComponentConfiguration) delete() error {
db := database.GetDB()
var so scenario.Scenario
@ -121,9 +121,9 @@ func (m *SimulationModel) delete() error {
return err
}
// remove association between SimulationModel and Scenario
// SimulationModel itself is not deleted from DB, it remains as "dangling"
err = db.Model(&so).Association("SimulationModels").Delete(m).Error
// remove association between ComponentConfiguration and Scenario
// ComponentConfiguration itself is not deleted from DB, it remains as "dangling"
err = db.Model(&so).Association("ComponentConfigurations").Delete(m).Error
return err
}

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, middleware.
/** component_configuration package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package simulationmodel
package component_configuration
import (
"fmt"
@ -30,22 +30,22 @@ import (
"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 {
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
}
modelID, err := helper.GetIDOfElement(c, "modelID", modelIDSource, modelIDBody)
configID, err := helper.GetIDOfElement(c, "configID", configIDSource, configIDBody)
if err != nil {
return false, m
}
err = m.ByID(uint(modelID))
err = m.ByID(uint(configID))
if helper.DBError(c, err) {
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>
* @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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package simulationmodel
package component_configuration
import (
"fmt"
@ -39,13 +39,15 @@ import (
var router *gin.Engine
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"`
ScenarioID uint `json:"scenarioID,omitempty"`
ICID uint `json:"icID,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
SelectedModelFileID uint `json:"selectedModelFileID,omitempty"`
SelectedFileID uint `json:"selectedFileID,omitempty"`
}
type ICRequest struct {
@ -66,7 +68,7 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
// authenticate as admin
token, _ := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.AdminCredentials)
base_api_auth, "POST", helper.AdminCredentials)
// POST $newICA
newICA := ICRequest{
@ -95,7 +97,7 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
// authenticate as normal user
token, _ = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
// POST $newScenario
newScenario := ScenarioRequest{
@ -133,18 +135,18 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate"))
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
// that can be associated with a new simulation model
// that can be associated with a new component configuration
scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
// 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
infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
os.Exit(m.Run())
}
func TestAddSimulationModel(t *testing.T) {
func TestAddConfig(t *testing.T) {
database.DropTables(db)
database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -154,92 +156,92 @@ func TestAddSimulationModel(t *testing.T) {
// using the respective endpoints of the API
scenarioID, ICID := addScenarioAndIC()
newSimulationModel := SimulationModelRequest{
Name: database.SimulationModelA.Name,
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
StartParameters: database.ConfigA.StartParameters,
SelectedFileID: database.ConfigA.SelectedFileID,
}
// authenticate as normal userB who has no access to new scenario
token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials)
base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err)
// try to POST with no access
// should result in unprocessable entity
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.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err)
// try to POST non JSON body
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.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err)
// test POST models/ $newSimulationModel
// test POST newConfig
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare POST's response with the newSimulationModel
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel})
// Compare POST's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err)
// Read newSimulationModel's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp)
// Read newConfig's ID from the response
newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err)
// Get the newSimulationModel
// Get the newConfig
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the newSimulationModel
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel})
// Compare GET's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err)
// try to POST a malformed simulation model
// try to POST a malformed component config
// Required fields are missing
malformedNewSimulationModel := SimulationModelRequest{
malformedNewConfig := ConfigRequest{
Name: "ThisIsAMalformedRequest",
}
// this should NOT work and return a unprocessable entity 442 status code
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.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials)
base_api_auth, "POST", helper.UserBCredentials)
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
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.Equalf(t, 422, code, "Response body: \n%v\n", resp)
}
func TestUpdateSimulationModel(t *testing.T) {
func TestUpdateConfig(t *testing.T) {
database.DropTables(db)
database.MigrateModels(db)
@ -252,107 +254,107 @@ func TestUpdateSimulationModel(t *testing.T) {
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err)
// test POST models/ $newSimulationModel
newSimulationModel := SimulationModelRequest{
Name: database.SimulationModelA.Name,
// test POST newConfig
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
StartParameters: database.ConfigA.StartParameters,
SelectedFileID: database.ConfigA.SelectedFileID,
}
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulationModel's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp)
// Read newConfig's ID from the response
newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err)
updatedSimulationModel := SimulationModelRequest{
Name: database.SimulationModelB.Name,
StartParameters: database.SimulationModelB.StartParameters,
updatedConfig := ConfigRequest{
Name: database.ConfigB.Name,
StartParameters: database.ConfigB.StartParameters,
}
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials)
base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err)
// try to PUT with no access
// should result in unprocessable entity
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.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,
"/api/authenticate", "POST", helper.GuestCredentials)
base_api_auth, "POST", helper.GuestCredentials)
assert.NoError(t, err)
// try to PUT as guest
// should NOT work and result in unprocessable entity
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.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err)
// try to PUT a non JSON body
// should result in a bad request
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.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// test PUT
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updatedSimulationModel
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel})
// Compare PUT's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err)
//Change IC ID to use second IC available in DB
updatedSimulationModel.ICID = ICID + 1
updatedConfig.ICID = ICID + 1
// test PUT again
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updatedSimulationModel
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel})
// Compare PUT's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err)
// Get the updatedSimulationModel
// Get the updateConfig
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the updatedSimulationModel
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel})
// Compare GET's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
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,
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.Equalf(t, 404, code, "Response body: \n%v\n", resp)
}
func TestDeleteSimulationModel(t *testing.T) {
func TestDeleteConfig(t *testing.T) {
database.DropTables(db)
database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -362,70 +364,70 @@ func TestDeleteSimulationModel(t *testing.T) {
// using the respective endpoints of the API
scenarioID, ICID := addScenarioAndIC()
newSimulationModel := SimulationModelRequest{
Name: database.SimulationModelA.Name,
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
StartParameters: database.ConfigA.StartParameters,
SelectedFileID: database.ConfigA.SelectedFileID,
}
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err)
// test POST models/ $newSimulationModel
// test POST newConfig
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulationModel's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp)
// Read newConfig's ID from the response
newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials)
base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err)
// try to DELETE with no access
// should result in unprocessable entity
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.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
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,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil)
fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err)
// Delete the added newSimulationModel
// Delete the added newConfig
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare DELETE's response with the newSimulationModel
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel})
// Compare DELETE's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
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,
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.Equal(t, initialNumber-1, finalNumber)
}
func TestGetAllSimulationModelsOfScenario(t *testing.T) {
func TestGetAllConfigsOfScenario(t *testing.T) {
database.DropTables(db)
database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -437,38 +439,38 @@ func TestGetAllSimulationModelsOfScenario(t *testing.T) {
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err)
// test POST models/ $newSimulationModel
newSimulationModel := SimulationModelRequest{
Name: database.SimulationModelA.Name,
// test POST newConfig
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
StartParameters: database.ConfigA.StartParameters,
SelectedFileID: database.ConfigA.SelectedFileID,
}
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.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Count the number of all the simulation models returned for scenario
NumberOfSimulationModels, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil)
// Count the number of all the component config returned for scenario
NumberOfConfigs, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equal(t, 1, NumberOfSimulationModels)
assert.Equal(t, 1, NumberOfConfigs)
// authenticate as normal userB who has no access to scenario
token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials)
base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err)
// try to get models without access
// try to get configs without access
// should result in unprocessable entity
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.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"
"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"
)
@ -43,23 +43,23 @@ func RegisterFileEndpoints(r *gin.RouterGroup) {
}
// 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
// @Tags files
// @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 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @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 objectID query int true "ID of either model or widget of which files are requested"
// @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 config or widget of which files are requested"
// @Router /files [get]
func getFiles(c *gin.Context) {
var err error
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))
return
}
@ -72,10 +72,10 @@ func getFiles(c *gin.Context) {
//Check access
var ok bool
var m simulationmodel.SimulationModel
var m component_configuration.ComponentConfiguration
var w widget.Widget
if objectType == "model" {
ok, m = simulationmodel.CheckPermissions(c, database.Read, "body", objectID)
if objectType == "config" {
ok, m = component_configuration.CheckPermissions(c, database.Read, "body", objectID)
} else {
ok, w = widget.CheckPermissions(c, database.Read, objectID)
}
@ -88,7 +88,7 @@ func getFiles(c *gin.Context) {
var files []database.File
if objectType == "model" {
if objectType == "config" {
err = db.Order("ID asc").Model(&m).Related(&files, "Files").Error
} else {
err = db.Order("ID asc").Model(&w).Related(&files, "Files").Error
@ -101,7 +101,7 @@ func getFiles(c *gin.Context) {
}
// 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
// @Tags files
// @Produce json
@ -118,13 +118,13 @@ func getFiles(c *gin.Context) {
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token"
// @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 objectID query int true "ID of either model or widget of which files are requested"
// @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 config or widget of which files are requested"
// @Router /files [post]
func addFile(c *gin.Context) {
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))
return
}
@ -137,8 +137,8 @@ func addFile(c *gin.Context) {
// Check access
var ok bool
if objectType == "model" {
ok, _ = simulationmodel.CheckPermissions(c, database.Update, "body", objectID)
if objectType == "config" {
ok, _ = component_configuration.CheckPermissions(c, database.Update, "body", objectID)
if !ok {
return
}

View file

@ -31,7 +31,7 @@ import (
"time"
"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"
)
@ -84,14 +84,14 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
f.ImageWidth = 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 err error
if objectType == "model" {
// check if model exists
if objectType == "config" {
// check if config exists
err = m.ByID(objectID)
f.WidgetID = 0
f.SimulationModelID = objectID
f.ConfigID = objectID
if err != nil {
return err
}
@ -99,7 +99,7 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
} else {
// check if widget exists
f.WidgetID = objectID
f.SimulationModelID = 0
f.ConfigID = 0
err = w.ByID(uint(objectID))
if err != nil {
return err
@ -122,8 +122,8 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
return err
}
// Create association to model or widget
if objectType == "model" {
// Create association to config or widget
if objectType == "config" {
db := database.GetDB()
err := db.Model(&m).Association("Files").Append(f).Error
if err != nil {
@ -174,9 +174,9 @@ func (f *File) delete() error {
return err
}
} else {
// remove association between file and simulation model
var m simulationmodel.SimulationModel
err := m.ByID(f.SimulationModelID)
// remove association between file and config
var m component_configuration.ComponentConfiguration
err := m.ByID(f.ConfigID)
if err != nil {
return err
}

View file

@ -25,7 +25,7 @@ import (
"fmt"
"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/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"
"github.com/gin-gonic/gin"
)
@ -50,8 +50,8 @@ func checkPermissions(c *gin.Context, operation database.CRUD) (bool, File) {
return false, f
}
if f.SimulationModelID > 0 {
ok, _ := simulationmodel.CheckPermissions(c, operation, "body", int(f.SimulationModelID))
if f.ConfigID > 0 {
ok, _ := component_configuration.CheckPermissions(c, operation, "body", int(f.ConfigID))
if !ok {
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/database"
"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/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/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
"github.com/gin-gonic/gin"
@ -49,7 +49,7 @@ import (
var router *gin.Engine
var db *gorm.DB
type SimulationModelRequest struct {
type ConfigRequest struct {
Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"`
ICID uint `json:"icID,omitempty"`
@ -91,7 +91,7 @@ type WidgetRequest struct {
CustomProperties postgres.Jsonb `json:"customProperties,omitempty"`
}
func addScenarioAndICAndSimulationModelAndDashboardAndWidget() (scenarioID uint, ICID uint, simulationModelID uint, dashboardID uint, widgetID uint) {
func addScenarioAndICAndConfigAndDashboardAndWidget() (scenarioID uint, ICID uint, configID uint, dashboardID uint, widgetID uint) {
// authenticate as admin
token, _ := helper.AuthenticateForTest(router,
@ -127,18 +127,18 @@ func addScenarioAndICAndSimulationModelAndDashboardAndWidget() (scenarioID uint,
// Read newScenario's ID from the response
newScenarioID, _ := helper.GetResponseID(resp)
// POST new simulation model
newSimulationModel := SimulationModelRequest{
Name: database.SimulationModelA.Name,
// POST new component config
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: uint(newScenarioID),
ICID: uint(newICID),
StartParameters: database.SimulationModelA.StartParameters,
StartParameters: database.ConfigA.StartParameters,
}
_, 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
newSimulationModelID, _ := helper.GetResponseID(resp)
// Read newConfig's ID from the response
newConfigID, _ := helper.GetResponseID(resp)
// POST new dashboard
newDashboard := DashboardRequest{
@ -177,7 +177,7 @@ func addScenarioAndICAndSimulationModelAndDashboardAndWidget() (scenarioID uint,
_, resp, _ = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
return uint(newScenarioID), uint(newICID), uint(newSimulationModelID), uint(newDashboardID), uint(newWidgetID)
return uint(newScenarioID), uint(newICID), uint(newConfigID), uint(newDashboardID), uint(newWidgetID)
}
func TestMain(m *testing.M) {
@ -196,14 +196,14 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate"))
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
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models"))
component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// 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"))
// 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
infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
// dashboard endpoints required here to first add a dashboard to the DB
// that can be associated with a new widget
@ -224,7 +224,7 @@ func TestAddFile(t *testing.T) {
// prepare the content of the DB for testing
// using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndICAndSimulationModelAndDashboardAndWidget()
_, _, configID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router,
@ -233,10 +233,10 @@ func TestAddFile(t *testing.T) {
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
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.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
// should return a bad request error
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.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// try to POST an invalid file
// should return a bad request
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.Equalf(t, 400, code, "Response body: \n%v\n", resp)
@ -299,7 +299,7 @@ func TestAddFile(t *testing.T) {
// Create the request
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")
req.Header.Set("Content-Type", contentType)
@ -340,7 +340,7 @@ func TestUpdateFile(t *testing.T) {
// prepare the content of the DB for testing
// using the respective endpoints of the API
_, _, simulationModelID, _, _ := addScenarioAndICAndSimulationModelAndDashboardAndWidget()
_, _, configID, _, _ := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
@ -372,7 +372,7 @@ func TestUpdateFile(t *testing.T) {
// Create the POST request
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")
req.Header.Set("Content-Type", contentType)
@ -474,7 +474,7 @@ func TestDeleteFile(t *testing.T) {
// prepare the content of the DB for testing
// using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndICAndSimulationModelAndDashboardAndWidget()
_, _, configID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
@ -504,7 +504,7 @@ func TestDeleteFile(t *testing.T) {
// Create the request
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")
req.Header.Set("Content-Type", contentType)
req.Header.Add("Authorization", "Bearer "+token)
@ -542,7 +542,7 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.UserBCredentials)
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
code, resp, err := helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil)
@ -561,9 +561,9 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials)
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,
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)
// try to DELETE non-existing fileID
@ -578,7 +578,7 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.GuestCredentials)
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
code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil)
@ -609,15 +609,15 @@ func TestDeleteFile(t *testing.T) {
assert.NoError(t, err)
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,
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.Equal(t, initialNumber-1, finalNumber)
}
func TestGetAllFilesOfSimulationModel(t *testing.T) {
func TestGetAllFilesOfConfig(t *testing.T) {
database.DropTables(db)
database.MigrateModels(db)
@ -625,17 +625,17 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
// prepare the content of the DB for testing
// using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndICAndSimulationModelAndDashboardAndWidget()
_, _, ConfigID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials)
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
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.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
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.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
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.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// Count the number of all files returned for simulation model
initialNumberModel, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil)
// Count the number of all files returned for component config
initialNumberConfig, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
assert.NoError(t, err)
// Count the number of all files returned for widget
@ -683,30 +683,30 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
assert.NoError(t, err, "opening file")
defer fh.Close()
// test POST a file to simulation model and widget
bodyBufModel1 := &bytes.Buffer{}
// test POST a file to component config and widget
bodyBufConfig1 := &bytes.Buffer{}
bodyBufWidget1 := &bytes.Buffer{}
bodyWriterModel1 := multipart.NewWriter(bodyBufModel1)
bodyWriterConfig1 := multipart.NewWriter(bodyBufConfig1)
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")
fileWriterWidget1, err := bodyWriterWidget1.CreateFormFile("file", "testuploadfile.txt")
assert.NoError(t, err, "writing to buffer")
// io copy
_, err = io.Copy(fileWriterModel1, fh)
_, err = io.Copy(fileWriterConfig1, fh)
assert.NoError(t, err, "IO copy")
_, err = io.Copy(fileWriterWidget1, fh)
assert.NoError(t, err, "IO copy")
contentTypeModel1 := bodyWriterModel1.FormDataContentType()
contentTypeConfig1 := bodyWriterConfig1.FormDataContentType()
contentTypeWidget1 := bodyWriterWidget1.FormDataContentType()
bodyWriterModel1.Close()
bodyWriterConfig1.Close()
bodyWriterWidget1.Close()
// Create the request for simulation model
// Create the request for component config
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")
req.Header.Set("Content-Type", contentTypeModel1)
req.Header.Set("Content-Type", contentTypeConfig1)
req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req)
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)
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
fh2, err := os.Open("testfile.txt")
assert.NoError(t, err, "opening file")
defer fh2.Close()
bodyBufModel2 := &bytes.Buffer{}
bodyBufConfig2 := &bytes.Buffer{}
bodyBufWidget2 := &bytes.Buffer{}
bodyWriterModel2 := multipart.NewWriter(bodyBufModel2)
bodyWriterConfig2 := multipart.NewWriter(bodyBufConfig2)
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")
fileWriterWidget2, err := bodyWriterWidget2.CreateFormFile("file", "testuploadfile2.txt")
assert.NoError(t, err, "writing to buffer")
// io copy
_, err = io.Copy(fileWriterModel2, fh2)
_, err = io.Copy(fileWriterConfig2, fh2)
assert.NoError(t, err, "IO copy")
_, err = io.Copy(fileWriterWidget2, fh2)
assert.NoError(t, err, "IO copy")
contentTypeModel2 := bodyWriterModel2.FormDataContentType()
contentTypeConfig2 := bodyWriterConfig2.FormDataContentType()
contentTypeWidget2 := bodyWriterWidget2.FormDataContentType()
bodyWriterModel2.Close()
bodyWriterConfig2.Close()
bodyWriterWidget2.Close()
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")
req3.Header.Set("Content-Type", contentTypeModel2)
req3.Header.Set("Content-Type", contentTypeConfig2)
req3.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w3, req3)
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)
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
finalNumberModel, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil)
// Again count the number of all the files returned for component config
finalNumberConfig, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
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
finalNumberWidget, err := helper.LengthOfResponse(router, token,

View file

@ -209,7 +209,7 @@ func deleteIC(c *gin.Context) {
// @ID getConfigsOfIC
// @Tags infrastructure-components
// @Produce json
// @Success 200 {object} docs.ResponseSimulationModels "Configs requested by user"
// @Success 200 {object} docs.ResponseConfigs "Configs requested by user"
// @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"

View file

@ -54,7 +54,7 @@ func (s *InfrastructureComponent) update(updatedIC InfrastructureComponent) erro
func (s *InfrastructureComponent) delete() error {
db := database.GetDB()
no_configs := db.Model(s).Association("SimulationModels").Count()
no_configs := db.Model(s).Association("ComponentConfigurations").Count()
if no_configs > 0 {
return fmt.Errorf("Infrastructure Component cannot be deleted as it is still used in configurations (active or dangling)")
@ -65,9 +65,9 @@ func (s *InfrastructureComponent) delete() error {
return err
}
func (s *InfrastructureComponent) getConfigs() ([]database.SimulationModel, int, error) {
func (s *InfrastructureComponent) getConfigs() ([]database.ComponentConfiguration, int, error) {
db := database.GetDB()
var configs []database.SimulationModel
err := db.Order("ID asc").Model(s).Related(&configs, "SimulationModels").Error
var configs []database.ComponentConfiguration
err := db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
return configs, len(configs), err
}

View file

@ -448,7 +448,7 @@ func TestGetConfigsOfIC(t *testing.T) {
assert.NoError(t, err)
// 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?
numberOfConfigs, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil)
assert.NoError(t, err)
@ -462,7 +462,7 @@ func TestGetConfigsOfIC(t *testing.T) {
assert.NoError(t, err)
// 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?
numberOfConfigs, err = helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil)
assert.NoError(t, err)

View file

@ -37,10 +37,10 @@ var (
},
)
SimulationModelCounter = prometheus.NewCounter(
ComponentConfigurationCounter = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "simulation_models",
Help: "A counter for the total number of simulation models",
Name: "component_configurations",
Help: "A counter for the total number of component configurations",
},
)
@ -103,7 +103,7 @@ func RegisterMetricsEndpoint(rg *gin.RouterGroup) {
// Register metrics
prometheus.MustRegister(
ICCounter,
SimulationModelCounter,
ComponentConfigurationCounter,
FileCounter,
ScenarioCounter,
UserCounter,
@ -112,17 +112,17 @@ func RegisterMetricsEndpoint(rg *gin.RouterGroup) {
}
func InitCounters(db *gorm.DB) {
var infrastructure_components, simulation_models, files, scenarios, users, dashboards float64
var infrastructure_components, component_configurations, files, scenarios, users, dashboards float64
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("scenarios").Count(&scenarios)
db.Table("users").Count(&users)
db.Table("dashboards").Count(&dashboards)
ICCounter.Add(infrastructure_components)
SimulationModelCounter.Add(simulation_models)
ComponentConfigurationCounter.Add(component_configurations)
FileCounter.Add(files)
ScenarioCounter.Add(scenarios)
UserCounter.Add(users)

View file

@ -82,7 +82,7 @@ func getScenarios(c *gin.Context) {
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})
}
@ -211,7 +211,7 @@ func getScenario(c *gin.Context) {
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})
}

View file

@ -28,7 +28,7 @@ import (
"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/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
)
func RegisterSignalEndpoints(r *gin.RouterGroup) {
@ -45,8 +45,8 @@ func RegisterSignalEndpoints(r *gin.RouterGroup) {
// @Produce json
// @Tags signals
// @Param direction query string true "Direction of signal (in or out)"
// @Param modelID query string true "Model ID of signals to be obtained"
// @Success 200 {object} docs.ResponseSignals "Signals which belong to simulation model"
// @Param configID query string true "Config ID of signals to be obtained"
// @Success 200 {object} docs.ResponseSignals "Signals which belong to component configuration"
// @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
@ -54,7 +54,7 @@ func RegisterSignalEndpoints(r *gin.RouterGroup) {
// @Router /signals [get]
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 {
return
}
@ -80,7 +80,7 @@ func getSignals(c *gin.Context) {
}
// 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
// @Accept json
// @Produce json
@ -91,7 +91,7 @@ func getSignals(c *gin.Context) {
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error"
// @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]
func addSignal(c *gin.Context) {
@ -110,13 +110,13 @@ func addSignal(c *gin.Context) {
// Create the new signal from the request
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 {
return
}
// Add signal to model
err := newSignal.addToSimulationModel()
// Add signal to component configuration
err := newSignal.addToConfig()
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"signal": newSignal.Signal})
}

View file

@ -23,7 +23,7 @@ package signal
import (
"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 {
@ -45,10 +45,10 @@ func (s *Signal) byID(id uint) error {
return nil
}
func (s *Signal) addToSimulationModel() error {
func (s *Signal) addToConfig() error {
db := database.GetDB()
var m simulationmodel.SimulationModel
err := m.ByID(s.SimulationModelID)
var m component_configuration.ComponentConfiguration
err := m.ByID(s.ConfigID)
if err != nil {
return err
}
@ -59,7 +59,7 @@ func (s *Signal) addToSimulationModel() error {
return err
}
// associate signal with simulation model in correct direction
// associate signal with component configuration in correct direction
if s.Direction == "in" {
err = db.Model(&m).Association("InputMapping").Append(s).Error
if err != nil {
@ -99,13 +99,13 @@ func (s *Signal) update(modifiedSignal Signal) error {
func (s *Signal) delete() error {
db := database.GetDB()
var m simulationmodel.SimulationModel
err := m.ByID(s.SimulationModelID)
var m component_configuration.ComponentConfiguration
err := m.ByID(s.ConfigID)
if err != nil {
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"
if s.Direction == "in" {
err = db.Model(&m).Association("InputMapping").Delete(s).Error

View file

@ -27,7 +27,7 @@ import (
"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/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) {
@ -50,7 +50,7 @@ func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) {
return false, sig
}
ok, _ := simulationmodel.CheckPermissions(c, operation, "body", int(sig.SimulationModelID))
ok, _ := component_configuration.CheckPermissions(c, operation, "body", int(sig.ConfigID))
if !ok {
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/database"
"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/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
@ -46,10 +46,10 @@ type SignalRequest struct {
Unit string `json:"unit,omitempty"`
Index uint `json:"index,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"`
ScenarioID uint `json:"scenarioID,omitempty"`
ICID uint `json:"icID,omitempty"`
@ -70,7 +70,7 @@ type ScenarioRequest struct {
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
}
func addScenarioAndICAndSimulationModel() (scenarioID uint, ICID uint, simulationModelID uint) {
func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
// authenticate as admin
token, _ := helper.AuthenticateForTest(router,
@ -106,24 +106,24 @@ func addScenarioAndICAndSimulationModel() (scenarioID uint, ICID uint, simulatio
// Read newScenario's ID from the response
newScenarioID, _ := helper.GetResponseID(resp)
// test POST models/ $newSimulationModel
newSimulationModel := SimulationModelRequest{
Name: database.SimulationModelA.Name,
// test POST newConfig
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: uint(newScenarioID),
ICID: uint(newICID),
StartParameters: database.SimulationModelA.StartParameters,
StartParameters: database.ConfigA.StartParameters,
}
_, 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
newSimulationModelID, _ := helper.GetResponseID(resp)
// Read newConfig's ID from the response
newConfigID, _ := helper.GetResponseID(resp)
// add the guest user to the new scenario
_, resp, _ = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
return uint(newScenarioID), uint(newICID), uint(newSimulationModelID)
return uint(newScenarioID), uint(newICID), uint(newConfigID)
}
func TestMain(m *testing.M) {
@ -143,14 +143,14 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true))
// simulationmodel endpoints required here to first add a simulation to the DB
// that can be associated with a new signal model
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models"))
// component-configuration endpoints required here to first add a component config to the DB
// that can be associated with a new signal
component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// 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"))
// 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
infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
RegisterSignalEndpoints(api.Group("/signals"))
@ -165,7 +165,7 @@ func TestAddSignal(t *testing.T) {
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
// using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel()
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
@ -177,7 +177,7 @@ func TestAddSignal(t *testing.T) {
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
// 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)
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
code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -260,7 +260,7 @@ func TestUpdateSignal(t *testing.T) {
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
// using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel()
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
@ -273,7 +273,7 @@ func TestUpdateSignal(t *testing.T) {
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -362,7 +362,7 @@ func TestDeleteSignal(t *testing.T) {
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
// using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel()
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
@ -375,7 +375,7 @@ func TestDeleteSignal(t *testing.T) {
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -403,9 +403,9 @@ func TestDeleteSignal(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials)
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,
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)
// 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,
Direction: database.OutSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalout})
@ -435,9 +435,9 @@ func TestDeleteSignal(t *testing.T) {
err = helper.CompareResponse(resp, helper.KeyModels{"signal": newSignal})
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,
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.Equal(t, initialNumber-1, finalNumber)
@ -449,7 +449,7 @@ func TestDeleteSignal(t *testing.T) {
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.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -457,16 +457,16 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
// using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel()
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials)
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,
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)
// test POST signals/ $newSignal
@ -475,7 +475,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalA})
@ -488,7 +488,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.InSignalB.Unit,
Direction: database.InSignalB.Direction,
Index: 2,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalB})
@ -501,7 +501,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalAout})
@ -514,30 +514,30 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.OutSignalB.Unit,
Direction: database.OutSignalB.Direction,
Index: 1,
SimulationModelID: simulationModelID,
ConfigID: configID,
}
code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalBout})
assert.NoError(t, err)
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,
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.Equal(t, initialNumber+2, finalNumber)
// Get the number of output signals
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.Equal(t, initialNumber+2, outputNumber)
// Try to get all signals for non-existing direction
// should result in bad request
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.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
// should result in unprocessable entity
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.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"`
Index uint `form:"index" validate:"required"`
Direction string `form:"direction" validate:"required,oneof=in out"`
SimulationModelID uint `form:"simulationModelID" validate:"required"`
ConfigID uint `form:"configID" validate:"required"`
}
type validUpdatedSignal struct {
@ -68,7 +68,7 @@ func (r *addSignalRequest) createSignal() Signal {
s.Unit = r.Signal.Unit
s.Index = r.Signal.Index
s.Direction = r.Signal.Direction
s.SimulationModelID = r.Signal.SimulationModelID
s.ConfigID = r.Signal.ConfigID
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"`
ICID uint `form:"ICID" validate:"required"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"required"`
SelectedModelFileID uint `form:"SelectedModelFilID" validate:"omitempty"`
}
type validUpdatedSimulationModel struct {
Name string `form:"Name" validate:"omitempty"`
ICID uint `form:"ICID" 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.ICID = r.SimulationModel.ICID
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.ICID != 0 {
s.ICID = r.SimulationModel.ICID
}
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.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,
"/api/authenticate", "POST", helper.GuestCredentials)
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/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
"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/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/scenario"
"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/user"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
)
@ -114,7 +114,7 @@ func main() {
api.Use(user.Authentication(true))
scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models"))
component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
signal.RegisterSignalEndpoints(api.Group("/signals"))
dashboard.RegisterDashboardEndpoints(api.Group("/dashboards"))
widget.RegisterWidgetEndpoints(api.Group("/widgets"))