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",
StartParameters: postgres.Jsonb{startParametersA},
SelectedModelFileID: 3,
var ConfigA = ComponentConfiguration{
Name: "Example simulation",
StartParameters: postgres.Jsonb{startParametersA},
SelectedFileID: 3,
}
var SimulationModelB = SimulationModel{
Name: "SimulationModel_B",
StartParameters: postgres.Jsonb{startParametersB},
SelectedModelFileID: 4,
var ConfigB = ComponentConfiguration{
Name: "VILLASnode gateway X",
StartParameters: postgres.Jsonb{startParametersB},
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 {
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"`
type ConfigRequest struct {
Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"`
ICID uint `json:"icID,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,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,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
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,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
// test POST newConfig
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
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,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
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,
ScenarioID: scenarioID,
ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID,
// test POST newConfig
newConfig := ConfigRequest{
Name: database.ConfigA.Name,
ScenarioID: scenarioID,
ICID: ICID,
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,10 +54,10 @@ 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("InfrastructureComponent cannot be deleted as it is still used in configurations (active or dangling)")
return fmt.Errorf("Infrastructure Component cannot be deleted as it is still used in configurations (active or dangling)")
}
// delete InfrastructureComponent from DB (does NOT remain as 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"
@ -42,14 +42,14 @@ var router *gin.Engine
var db *gorm.DB
type SignalRequest struct {
Name string `json:"name,omitempty"`
Unit string `json:"unit,omitempty"`
Index uint `json:"index,omitempty"`
Direction string `json:"direction,omitempty"`
SimulationModelID uint `json:"simulationModelID,omitempty"`
Name string `json:"name,omitempty"`
Unit string `json:"unit,omitempty"`
Index uint `json:"index,omitempty"`
Direction string `json:"direction,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,
@ -173,11 +173,11 @@ func TestAddSignal(t *testing.T) {
assert.NoError(t, err)
newSignal := SignalRequest{
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
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,
@ -269,11 +269,11 @@ func TestUpdateSignal(t *testing.T) {
// test POST signals/ $newSignal
newSignal := SignalRequest{
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
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,
@ -371,11 +371,11 @@ func TestDeleteSignal(t *testing.T) {
// test POST signals/ $newSignal
newSignal := SignalRequest{
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
ConfigID: configID,
}
code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -403,18 +403,18 @@ 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
newSignalout := SignalRequest{
Name: database.OutSignalA.Name,
Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
Name: database.OutSignalA.Name,
Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction,
Index: 1,
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,25 +457,25 @@ 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
newSignalA := SignalRequest{
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
Name: database.InSignalA.Name,
Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction,
Index: 1,
ConfigID: configID,
}
code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalA})
@ -484,11 +484,11 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
// add a second input signal
newSignalB := SignalRequest{
Name: database.InSignalB.Name,
Unit: database.InSignalB.Unit,
Direction: database.InSignalB.Direction,
Index: 2,
SimulationModelID: simulationModelID,
Name: database.InSignalB.Name,
Unit: database.InSignalB.Unit,
Direction: database.InSignalB.Direction,
Index: 2,
ConfigID: configID,
}
code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalB})
@ -497,11 +497,11 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
// add an output signal
newSignalAout := SignalRequest{
Name: database.OutSignalA.Name,
Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction,
Index: 1,
SimulationModelID: simulationModelID,
Name: database.OutSignalA.Name,
Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction,
Index: 1,
ConfigID: configID,
}
code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalAout})
@ -510,34 +510,34 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
// add a second output signal
newSignalBout := SignalRequest{
Name: database.OutSignalB.Name,
Unit: database.OutSignalB.Unit,
Direction: database.OutSignalB.Direction,
Index: 1,
SimulationModelID: simulationModelID,
Name: database.OutSignalB.Name,
Unit: database.OutSignalB.Unit,
Direction: database.OutSignalB.Direction,
Index: 1,
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

@ -28,11 +28,11 @@ import (
var validate *validator.Validate
type validNewSignal struct {
Name string `form:"Name" validate:"required"`
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"`
Name string `form:"Name" validate:"required"`
Unit string `form:"unit" validate:"omitempty"`
Index uint `form:"index" validate:"required"`
Direction string `form:"direction" validate:"required,oneof=in out"`
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"))