mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
Fix duplication: synchronous duplication, proper duplication of widgets which use IDs, reuse duplicated IC (if alive)
This commit is contained in:
parent
61ead46392
commit
4db2f91ea5
4 changed files with 569 additions and 156 deletions
|
@ -100,5 +100,7 @@ deploy:
|
||||||
--dockerfile ${CI_PROJECT_DIR}/Dockerfile
|
--dockerfile ${CI_PROJECT_DIR}/Dockerfile
|
||||||
--destination ${DOCKER_IMAGE}:${DOCKER_TAG}
|
--destination ${DOCKER_IMAGE}:${DOCKER_TAG}
|
||||||
--snapshotMode=redo
|
--snapshotMode=redo
|
||||||
|
--single-snapshot
|
||||||
dependencies:
|
dependencies:
|
||||||
- test
|
- test
|
||||||
|
|
||||||
|
|
|
@ -287,10 +287,7 @@ func authenticateExternal(c *gin.Context) (User, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if groupedScenario.Duplicate {
|
if groupedScenario.Duplicate {
|
||||||
if err := <-duplicateScenarioForUser(so, &myUser.User, ""); err != nil {
|
duplicateScenarioForUser(so, &myUser.User, "")
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { // add user to scenario
|
} else { // add user to scenario
|
||||||
err = db.Model(&so).Association("Users").Append(&(myUser.User)).Error
|
err = db.Model(&so).Association("Users").Append(&(myUser.User)).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -27,102 +27,109 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/jinzhu/gorm/dialects/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
func duplicateScenarioForUser(s database.Scenario, user *database.User, uuidstr string) <-chan error {
|
func duplicateScenarioForUser(s database.Scenario, user *database.User, uuidstr string) {
|
||||||
errs := make(chan error, 1)
|
|
||||||
|
|
||||||
go func() {
|
// get all component configs of the scenario
|
||||||
|
db := database.GetDB()
|
||||||
|
var configs []database.ComponentConfiguration
|
||||||
|
err := db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warning: scenario to duplicate (id=%d) has no component configurations", s.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
icIdmap := make(map[uint]uint) // key: original IC id, value: duplicated IC id
|
||||||
|
duplicatedICuuids := make(map[uint]string) // key: original icID; value: UUID of duplicate
|
||||||
|
|
||||||
|
// iterate over component configs to check for ICs to duplicate
|
||||||
|
for _, config := range configs {
|
||||||
|
icID := config.ICID
|
||||||
|
|
||||||
|
if _, ok := duplicatedICuuids[icID]; ok { // this IC was already added
|
||||||
|
log.Println("IC already added while ranging configs")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var ic database.InfrastructureComponent
|
||||||
|
err = db.Find(&ic, icID).Error
|
||||||
|
|
||||||
// get all component configs of the scenario
|
|
||||||
db := database.GetDB()
|
|
||||||
var configs []database.ComponentConfiguration
|
|
||||||
err := db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Warning: scenario to duplicate (id=%d) has no component configurations", s.ID)
|
log.Printf("Cannot find IC with id %d in DB, will not duplicate for User %s: %s", icID, user.Username, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over component configs to check for ICs to duplicate
|
alreadyDuplicated, dupID := isICalreadyDuplicated(ic, user.Username)
|
||||||
duplicatedICuuids := make(map[uint]string) // key: original icID; value: UUID of duplicate
|
// create new kubernetes simulator OR use existing IC
|
||||||
var externalUUIDs []string // external ICs to wait for
|
if ic.Category == "simulator" && ic.Type == "kubernetes" && !alreadyDuplicated {
|
||||||
for _, config := range configs {
|
duplicateUUID, err := duplicateIC(ic, user.Username, uuidstr)
|
||||||
icID := config.ICID
|
|
||||||
if duplicatedICuuids[icID] != "" { // this IC was already added
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var ic database.InfrastructureComponent
|
|
||||||
err = db.Find(&ic, icID).Error
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Cannot find IC with id %d in DB, will not duplicate for User %s: %s", icID, user.Username, err)
|
log.Printf("duplication of IC (id=%d) unsuccessful, err: %s", icID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new kubernetes simulator OR use existing IC
|
duplicatedICuuids[ic.ID] = duplicateUUID
|
||||||
if ic.Category == "simulator" && ic.Type == "kubernetes" {
|
} else if alreadyDuplicated {
|
||||||
duplicateUUID, err := duplicateIC(ic, user.Username, uuidstr)
|
duplicatedICuuids[ic.ID] = "alreadyduplicated"
|
||||||
if err != nil {
|
icIdmap[ic.ID] = dupID
|
||||||
errs <- fmt.Errorf("duplication of IC (id=%d) unsuccessful, err: %s", icID, err)
|
err = nil
|
||||||
continue
|
} else { // use existing IC
|
||||||
}
|
duplicatedICuuids[ic.ID] = "useoriginal"
|
||||||
|
icIdmap[ic.ID] = ic.ID
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
duplicatedICuuids[ic.ID] = duplicateUUID
|
// copy scenario after all new external ICs are in DB
|
||||||
externalUUIDs = append(externalUUIDs, duplicateUUID)
|
icsToWaitFor := len(duplicatedICuuids)
|
||||||
} else { // use existing IC
|
var timeout = 20 // seconds
|
||||||
duplicatedICuuids[ic.ID] = ""
|
|
||||||
err = nil
|
for i := 0; i < timeout; i++ {
|
||||||
|
// duplicate scenario after all duplicated ICs have been found in the DB
|
||||||
|
log.Printf("Number of ICs to wait for: %d", icsToWaitFor)
|
||||||
|
if icsToWaitFor <= 0 {
|
||||||
|
err := duplicateScenario(s, icIdmap, user)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("duplicate scenario %v fails with error %v", s.Name, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy scenario after all new external ICs are in DB
|
// check for new ICs with previously created UUIDs
|
||||||
icsToWaitFor := len(externalUUIDs)
|
for icId, uuid_r := range duplicatedICuuids {
|
||||||
var timeout = 20 // seconds
|
if uuid_r == "alreadyduplicated" || uuid_r == "useoriginal" {
|
||||||
|
icsToWaitFor--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("Looking for duplicated IC with UUID %s", uuid_r)
|
||||||
|
|
||||||
for i := 0; i < timeout; i++ {
|
// a new IC is searched by UUID, otherwise by string comparison of IC name
|
||||||
// duplicate scenario after all duplicated ICs have been found in the DB
|
// this makes sense in testing and also in reality: if an external IC was requested
|
||||||
if icsToWaitFor == 0 {
|
// it should be checked for, checking shouldn't be omitted due to old duplicated IC
|
||||||
err := duplicateScenario(s, duplicatedICuuids, user)
|
var duplicatedIC database.InfrastructureComponent
|
||||||
if err != nil {
|
err = db.Find(&duplicatedIC, "UUID = ?", uuid_r).Error
|
||||||
errs <- fmt.Errorf("duplicate scenario %v fails with error %v", s.Name, err.Error())
|
if err != nil {
|
||||||
}
|
log.Printf("Didn't find duplicated IC: %s, keep waiting for it..", err)
|
||||||
|
|
||||||
close(errs)
|
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
time.Sleep(1 * time.Second)
|
log.Printf("Found duplicated IC! Original IC id: %d, duplicated IC id: %d", icId, duplicatedIC.ID)
|
||||||
}
|
icsToWaitFor--
|
||||||
|
icIdmap[icId] = duplicatedIC.ID
|
||||||
// check for new ICs with previously created UUIDs
|
uuid_r = ""
|
||||||
for _, uuid_r := range externalUUIDs {
|
|
||||||
if uuid_r == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Printf("Looking for duplicated IC with UUID %s", uuid_r)
|
|
||||||
var duplicatedIC database.InfrastructureComponent
|
|
||||||
err = db.Find(&duplicatedIC, "UUID = ?", uuid_r).Error
|
|
||||||
if err != nil {
|
|
||||||
errs <- fmt.Errorf("Error looking up duplicated IC: %s", err)
|
|
||||||
} else {
|
|
||||||
icsToWaitFor--
|
|
||||||
uuid_r = ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
errs <- fmt.Errorf("ALERT! Timed out while waiting for IC duplication, scenario not properly duplicated")
|
|
||||||
close(errs)
|
|
||||||
|
|
||||||
}()
|
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplicateScenario(s database.Scenario, icIds map[uint]string, user *database.User) error {
|
func duplicateScenario(s database.Scenario, icIds map[uint]uint, user *database.User) error {
|
||||||
|
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
|
||||||
|
@ -145,28 +152,34 @@ func duplicateScenario(s database.Scenario, icIds map[uint]string, user *databas
|
||||||
|
|
||||||
// duplicate files
|
// duplicate files
|
||||||
var files []database.File
|
var files []database.File
|
||||||
|
fileidmap := make(map[uint]uint) // key: original file id, value: duplicated file id
|
||||||
err = db.Order("ID asc").Model(s).Related(&files, "Files").Error
|
err = db.Order("ID asc").Model(s).Related(&files, "Files").Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting files for scenario %d", s.ID)
|
log.Printf("error getting files for scenario %d", s.ID)
|
||||||
}
|
}
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
err = duplicateFile(f, duplicateSo.ID)
|
duplicateFileID, err := duplicateFile(f, duplicateSo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error creating duplicate file %d: %s", f.ID, err)
|
log.Printf("error creating duplicate file %d: %s", f.ID, err)
|
||||||
continue
|
continue
|
||||||
|
} else {
|
||||||
|
fileidmap[f.ID] = duplicateFileID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var configs []database.ComponentConfiguration
|
var configs []database.ComponentConfiguration
|
||||||
|
configidmap := make(map[uint]uint) // key: original config id, value: duplicated config id
|
||||||
// map existing signal IDs to duplicated signal IDs for widget duplication
|
// map existing signal IDs to duplicated signal IDs for widget duplication
|
||||||
signalMap := make(map[uint]uint)
|
signalMap := make(map[uint]uint)
|
||||||
err = db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
|
err = db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, c := range configs {
|
for _, c := range configs {
|
||||||
err = duplicateComponentConfig(c, duplicateSo.ID, icIds, &signalMap)
|
duplicatConfigID, err := duplicateComponentConfig(c, duplicateSo.ID, icIds, &signalMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error duplicating component config %d: %s", c.ID, err)
|
log.Printf("Error duplicating component config %d: %s", c.ID, err)
|
||||||
continue
|
continue
|
||||||
|
} else {
|
||||||
|
configidmap[c.ID] = duplicatConfigID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -180,7 +193,7 @@ func duplicateScenario(s database.Scenario, icIds map[uint]string, user *databas
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dab := range dabs {
|
for _, dab := range dabs {
|
||||||
err = duplicateDashboard(dab, duplicateSo.ID, signalMap)
|
err = duplicateDashboard(dab, duplicateSo.ID, signalMap, configidmap, fileidmap, icIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error duplicating dashboard %d: %s", dab.ID, err)
|
log.Printf("Error duplicating dashboard %d: %s", dab.ID, err)
|
||||||
continue
|
continue
|
||||||
|
@ -190,7 +203,7 @@ func duplicateScenario(s database.Scenario, icIds map[uint]string, user *databas
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplicateFile(f database.File, scenarioID uint) error {
|
func duplicateFile(f database.File, scenarioID uint) (uint, error) {
|
||||||
|
|
||||||
var dup database.File
|
var dup database.File
|
||||||
dup.Name = f.Name
|
dup.Name = f.Name
|
||||||
|
@ -209,7 +222,7 @@ func duplicateFile(f database.File, scenarioID uint) error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
err := db.Create(&dup).Error
|
err := db.Create(&dup).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create association of duplicate file to scenario ID of duplicate file
|
// Create association of duplicate file to scenario ID of duplicate file
|
||||||
|
@ -217,15 +230,15 @@ func duplicateFile(f database.File, scenarioID uint) error {
|
||||||
var so database.Scenario
|
var so database.Scenario
|
||||||
err = db.Find(&so, scenarioID).Error
|
err = db.Find(&so, scenarioID).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Model(&so).Association("Files").Append(&dup).Error
|
err = db.Model(&so).Association("Files").Append(&dup).Error
|
||||||
|
|
||||||
return err
|
return dup.ID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplicateComponentConfig(m database.ComponentConfiguration, scenarioID uint, icIds map[uint]string, signalMap *map[uint]uint) error {
|
func duplicateComponentConfig(m database.ComponentConfiguration, scenarioID uint, icIds map[uint]uint, signalMap *map[uint]uint) (uint, error) {
|
||||||
|
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
|
||||||
|
@ -234,53 +247,53 @@ func duplicateComponentConfig(m database.ComponentConfiguration, scenarioID uint
|
||||||
dup.StartParameters = m.StartParameters
|
dup.StartParameters = m.StartParameters
|
||||||
dup.ScenarioID = scenarioID
|
dup.ScenarioID = scenarioID
|
||||||
|
|
||||||
if icIds[m.ICID] == "" {
|
if val, ok := icIds[m.ICID]; ok {
|
||||||
dup.ICID = m.ICID
|
|
||||||
} else {
|
|
||||||
var duplicatedIC database.InfrastructureComponent
|
var duplicatedIC database.InfrastructureComponent
|
||||||
err := db.Find(&duplicatedIC, "UUID = ?", icIds[m.ICID]).Error
|
err := db.Find(&duplicatedIC, "ID = ?", val).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
dup.ICID = duplicatedIC.ID
|
dup.ICID = duplicatedIC.ID
|
||||||
|
} else {
|
||||||
|
dup.ICID = m.ICID
|
||||||
}
|
}
|
||||||
|
|
||||||
// save duplicate to DB and create associations with IC and scenario
|
// save duplicate to DB and create associations with IC and scenario
|
||||||
var so database.Scenario
|
var so database.Scenario
|
||||||
err := db.Find(&so, scenarioID).Error
|
err := db.Find(&so, scenarioID).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// save component configuration to DB
|
// save component configuration to DB
|
||||||
err = db.Create(&dup).Error
|
err = db.Create(&dup).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// associate IC with component configuration
|
// associate IC with component configuration
|
||||||
var ic database.InfrastructureComponent
|
var ic database.InfrastructureComponent
|
||||||
err = db.Find(&ic, dup.ICID).Error
|
err = db.Find(&ic, dup.ICID).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
err = db.Model(&ic).Association("ComponentConfigurations").Append(&dup).Error
|
err = db.Model(&ic).Association("ComponentConfigurations").Append(&dup).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// associate component configuration with scenario
|
// associate component configuration with scenario
|
||||||
err = db.Model(&so).Association("ComponentConfigurations").Append(&dup).Error
|
err = db.Model(&so).Association("ComponentConfigurations").Append(&dup).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// duplication of signals
|
// duplication of signals
|
||||||
var sigs []database.Signal
|
var sigs []database.Signal
|
||||||
err = db.Order("ID asc").Model(&m).Related(&sigs, "OutputMapping").Error
|
err = db.Order("ID asc").Model(&m).Related(&sigs, "OutputMapping").Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
smap := *signalMap
|
smap := *signalMap
|
||||||
for _, s := range sigs {
|
for _, s := range sigs {
|
||||||
|
@ -295,7 +308,7 @@ func duplicateComponentConfig(m database.ComponentConfiguration, scenarioID uint
|
||||||
// save signal to DB
|
// save signal to DB
|
||||||
err = db.Create(&sigDup).Error
|
err = db.Create(&sigDup).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// associate signal with component configuration in correct direction
|
// associate signal with component configuration in correct direction
|
||||||
|
@ -306,16 +319,17 @@ func duplicateComponentConfig(m database.ComponentConfiguration, scenarioID uint
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
smap[s.ID] = sigDup.ID
|
smap[s.ID] = sigDup.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return dup.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplicateDashboard(d database.Dashboard, scenarioID uint, signalMap map[uint]uint) error {
|
func duplicateDashboard(d database.Dashboard, scenarioID uint, signalMap map[uint]uint,
|
||||||
|
configIDmap map[uint]uint, fileIDmap map[uint]uint, icIds map[uint]uint) error {
|
||||||
|
|
||||||
var duplicateD database.Dashboard
|
var duplicateD database.Dashboard
|
||||||
duplicateD.Grid = d.Grid
|
duplicateD.Grid = d.Grid
|
||||||
|
@ -351,7 +365,7 @@ func duplicateDashboard(d database.Dashboard, scenarioID uint, signalMap map[uin
|
||||||
}
|
}
|
||||||
for _, w := range widgets {
|
for _, w := range widgets {
|
||||||
|
|
||||||
err = duplicateWidget(w, duplicateD.ID, signalMap)
|
err = duplicateWidget(w, duplicateD.ID, signalMap, configIDmap, fileIDmap, icIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error creating duplicate for widget %d: %s", w.ID, err)
|
log.Printf("error creating duplicate for widget %d: %s", w.ID, err)
|
||||||
continue
|
continue
|
||||||
|
@ -361,10 +375,11 @@ func duplicateDashboard(d database.Dashboard, scenarioID uint, signalMap map[uin
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplicateWidget(w database.Widget, dashboardID uint, signalMap map[uint]uint) error {
|
func duplicateWidget(w database.Widget, dashboardID uint, signalMap map[uint]uint,
|
||||||
|
configIDmap map[uint]uint, fileIDmap map[uint]uint, icIds map[uint]uint) error {
|
||||||
|
|
||||||
var duplicateW database.Widget
|
var duplicateW database.Widget
|
||||||
duplicateW.DashboardID = dashboardID
|
duplicateW.DashboardID = dashboardID
|
||||||
duplicateW.CustomProperties = w.CustomProperties
|
|
||||||
duplicateW.Height = w.Height
|
duplicateW.Height = w.Height
|
||||||
duplicateW.Width = w.Width
|
duplicateW.Width = w.Width
|
||||||
duplicateW.MinHeight = w.MinHeight
|
duplicateW.MinHeight = w.MinHeight
|
||||||
|
@ -380,6 +395,16 @@ func duplicateWidget(w database.Widget, dashboardID uint, signalMap map[uint]uin
|
||||||
duplicateW.SignalIDs = append(duplicateW.SignalIDs, int64(signalMap[uint(id)]))
|
duplicateW.SignalIDs = append(duplicateW.SignalIDs, int64(signalMap[uint(id)]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.Type == "ICstatus" {
|
||||||
|
duplicateW.CustomProperties = duplicateICStatusCustomProps(w.CustomProperties, icIds)
|
||||||
|
} else if w.Type == "Player" {
|
||||||
|
duplicateW.CustomProperties = duplicatePlayerCustomProps(w.CustomProperties, configIDmap)
|
||||||
|
} else if w.Type == "Image" {
|
||||||
|
duplicateW.CustomProperties = duplicateImageCustomProps(w.CustomProperties, fileIDmap)
|
||||||
|
} else {
|
||||||
|
duplicateW.CustomProperties = w.CustomProperties
|
||||||
|
}
|
||||||
|
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
var dab database.Dashboard
|
var dab database.Dashboard
|
||||||
err := db.Find(&dab, duplicateW.DashboardID).Error
|
err := db.Find(&dab, duplicateW.DashboardID).Error
|
||||||
|
@ -398,6 +423,92 @@ func duplicateWidget(w database.Widget, dashboardID uint, signalMap map[uint]uin
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func duplicateICStatusCustomProps(customProps postgres.Jsonb, icIds map[uint]uint) postgres.Jsonb {
|
||||||
|
type ICstatusCustomProps struct {
|
||||||
|
CheckedIDs []uint `json:"checkedIDs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var props ICstatusCustomProps
|
||||||
|
err := json.Unmarshal(customProps.RawMessage, &props)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ICstatus duplication, unmarshalling failed: err: %s", err)
|
||||||
|
return customProps
|
||||||
|
}
|
||||||
|
|
||||||
|
var IDs []string
|
||||||
|
for _, id := range props.CheckedIDs {
|
||||||
|
IDs = append(IDs, strconv.FormatUint(uint64(icIds[id]), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
customProperties := fmt.Sprintf(`{"checkedIDs": [%s]}`, strings.Join(IDs, ","))
|
||||||
|
|
||||||
|
return postgres.Jsonb{RawMessage: json.RawMessage(customProperties)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func duplicatePlayerCustomProps(customProps postgres.Jsonb, configIDmap map[uint]uint) postgres.Jsonb {
|
||||||
|
type PlayerCustomProps struct {
|
||||||
|
ConfigID string `json:"configID"`
|
||||||
|
ConfigIDs []int `json:"configIDs"`
|
||||||
|
UploadResults bool `json:"uploadResults"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var props PlayerCustomProps
|
||||||
|
err := json.Unmarshal(customProps.RawMessage, &props)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Player duplication, unmarshalling failed: err: %v", err)
|
||||||
|
return customProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// get configID of original config
|
||||||
|
u, err := strconv.ParseUint(props.ConfigID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Player duplication, parsing file ID failed: err: %v", err)
|
||||||
|
return customProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// get configID of duplicated config, save it in PlayerCustomProps struct
|
||||||
|
props.ConfigID = strconv.FormatUint(uint64(configIDmap[uint(u)]), 10)
|
||||||
|
customProperties, err := json.Marshal(props)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Player duplication, marshalling failed: err: %v", err)
|
||||||
|
return customProps
|
||||||
|
}
|
||||||
|
|
||||||
|
return postgres.Jsonb{RawMessage: customProperties}
|
||||||
|
}
|
||||||
|
|
||||||
|
func duplicateImageCustomProps(customProps postgres.Jsonb, fileIDmap map[uint]uint) postgres.Jsonb {
|
||||||
|
type ImageCustomProps struct {
|
||||||
|
File string `json:"file"`
|
||||||
|
Update bool `json:"update"`
|
||||||
|
Lock bool `json:"lockAspect"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var props ImageCustomProps
|
||||||
|
err := json.Unmarshal(customProps.RawMessage, &props)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Image duplication, unmarshalling failed: err: %v", err)
|
||||||
|
return customProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// get fileID of original file
|
||||||
|
u, err := strconv.ParseUint(props.File, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Image duplication, parsing file ID failed: err: %v", err)
|
||||||
|
return customProps
|
||||||
|
}
|
||||||
|
// get fileID of duplicated file, save it in ImageCustomProps struct
|
||||||
|
props.File = strconv.FormatUint(uint64(fileIDmap[uint(u)]), 10)
|
||||||
|
customProperties, err := json.Marshal(props)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Image duplication, marshalling failed: err: %v", err)
|
||||||
|
return customProps
|
||||||
|
}
|
||||||
|
|
||||||
|
return postgres.Jsonb{RawMessage: customProperties}
|
||||||
|
}
|
||||||
|
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
|
@ -512,3 +623,24 @@ func duplicateIC(ic database.InfrastructureComponent, userName string, uuidstr s
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isICalreadyDuplicated(ic database.InfrastructureComponent, username string) (bool, uint) {
|
||||||
|
db := database.GetDB()
|
||||||
|
var duplicateICs []database.InfrastructureComponent
|
||||||
|
duplicateName := fmt.Sprintf("%s %s", ic.Name, username)
|
||||||
|
err := db.Find(&duplicateICs, "Name = ?", duplicateName).Error
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error looking for duplicated ICs: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the first duplicated IC that was recently updated
|
||||||
|
for _, value := range duplicateICs {
|
||||||
|
lastUpdate := value.UpdatedAt
|
||||||
|
diff := time.Since(lastUpdate)
|
||||||
|
if diff.Seconds() < 60 {
|
||||||
|
return true, value.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|
|
@ -884,14 +884,26 @@ func TestDuplicateScenarioForUser(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEqual(t, 99, fileID)
|
assert.NotEqual(t, 99, fileID)
|
||||||
|
|
||||||
// add IC
|
// add ICs (kubernetes simulator plus other)
|
||||||
err = addIC(session, token)
|
err = addICs(session, token)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// add component config
|
// add two component configs with the same IC (ID 1)
|
||||||
err = addComponentConfig(scenarioID, token)
|
// plus one component config with IC != kubernetes simulator (ID 2)
|
||||||
|
err = addComponentConfigs(scenarioID, token)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* component/IC test setup:
|
||||||
|
* C0 --> IC0
|
||||||
|
* C1 --> IC0
|
||||||
|
* C2 --> IC1
|
||||||
|
* ---- after duplication: ----
|
||||||
|
* C3 --> IC2
|
||||||
|
* C4 --> IC2
|
||||||
|
* C5 --> IC1
|
||||||
|
*/
|
||||||
|
|
||||||
// add signals
|
// add signals
|
||||||
err = addSignals(token)
|
err = addSignals(token)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -919,9 +931,7 @@ func TestDuplicateScenarioForUser(t *testing.T) {
|
||||||
err = addFakeIC(uuidDup, session, token)
|
err = addFakeIC(uuidDup, session, token)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
if err := <-duplicateScenarioForUser(originalSo, &myUser.User, uuidDup); err != nil {
|
duplicateScenarioForUser(originalSo, &myUser.User, uuidDup)
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** Check duplicated scenario for correctness ***/
|
/*** Check duplicated scenario for correctness ***/
|
||||||
var dplScenarios []database.Scenario
|
var dplScenarios []database.Scenario
|
||||||
|
@ -947,15 +957,26 @@ func TestDuplicateScenarioForUser(t *testing.T) {
|
||||||
var configs []database.ComponentConfiguration
|
var configs []database.ComponentConfiguration
|
||||||
err = db.Find(&configs).Error
|
err = db.Find(&configs).Error
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 2, len(configs))
|
assert.Equal(t, 6, len(configs))
|
||||||
assert.Equal(t, configs[0].Name, configs[1].Name)
|
assert.Equal(t, configs[0].Name, configs[3].Name)
|
||||||
assert.Equal(t, configs[0].FileIDs, configs[1].FileIDs)
|
assert.Equal(t, configs[0].FileIDs, configs[3].FileIDs)
|
||||||
assert.Equal(t, configs[0].InputMapping, configs[1].InputMapping)
|
assert.Equal(t, configs[0].InputMapping, configs[3].InputMapping)
|
||||||
assert.Equal(t, configs[0].OutputMapping, configs[1].OutputMapping)
|
assert.Equal(t, configs[0].OutputMapping, configs[3].OutputMapping)
|
||||||
assert.Equal(t, configs[0].StartParameters, configs[1].StartParameters)
|
assert.Equal(t, configs[0].StartParameters, configs[3].StartParameters)
|
||||||
assert.NotEqual(t, configs[0].ScenarioID, configs[1].ScenarioID)
|
assert.NotEqual(t, configs[0].ScenarioID, configs[3].ScenarioID)
|
||||||
assert.NotEqual(t, configs[0].ICID, configs[1].ICID)
|
assert.NotEqual(t, configs[0].ICID, configs[3].ICID) // original and duplicated IC
|
||||||
assert.NotEqual(t, configs[0].ID, configs[1].ID)
|
assert.NotEqual(t, configs[0].ID, configs[3].ID)
|
||||||
|
|
||||||
|
assert.Equal(t, configs[0].ScenarioID, configs[1].ScenarioID)
|
||||||
|
assert.Equal(t, configs[0].ScenarioID, configs[2].ScenarioID)
|
||||||
|
assert.Equal(t, configs[3].ScenarioID, configs[4].ScenarioID)
|
||||||
|
assert.Equal(t, configs[3].ScenarioID, configs[5].ScenarioID)
|
||||||
|
|
||||||
|
assert.Equal(t, configs[0].ICID, configs[1].ICID) // same IC for both configs
|
||||||
|
assert.Equal(t, configs[3].ICID, configs[4].ICID) // same duplicated IC
|
||||||
|
assert.Equal(t, configs[2].ICID, configs[5].ICID) // reused (not duplicated) IC
|
||||||
|
assert.NotEqual(t, configs[0].ICID, configs[2].ICID)
|
||||||
|
assert.NotEqual(t, configs[0].ICID, configs[3].ICID)
|
||||||
|
|
||||||
// compare original and duplicated signals
|
// compare original and duplicated signals
|
||||||
var signals []database.Signal
|
var signals []database.Signal
|
||||||
|
@ -983,17 +1004,28 @@ func TestDuplicateScenarioForUser(t *testing.T) {
|
||||||
|
|
||||||
// compare original and duplicated infrastructure component
|
// compare original and duplicated infrastructure component
|
||||||
var ics []database.InfrastructureComponent
|
var ics []database.InfrastructureComponent
|
||||||
err = db.Find(&ics).Error
|
err = db.Order("created_at asc").Find(&ics).Error
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 2, len(ics))
|
assert.Equal(t, 3, len(ics))
|
||||||
assert.Equal(t, ics[0].Name, ics[1].Name)
|
assert.Equal(t, ics[0].Category, ics[2].Category)
|
||||||
assert.Equal(t, ics[0].Category, ics[1].Category)
|
assert.Equal(t, ics[0].Type, ics[2].Type)
|
||||||
assert.Equal(t, ics[0].Type, ics[1].Type)
|
assert.Equal(t, ics[0].CreateParameterSchema, ics[2].CreateParameterSchema)
|
||||||
assert.Equal(t, ics[0].CreateParameterSchema, ics[1].CreateParameterSchema)
|
assert.Equal(t, ics[0].StartParameterSchema, ics[2].StartParameterSchema)
|
||||||
assert.Equal(t, ics[0].StartParameterSchema, ics[1].StartParameterSchema)
|
assert.Equal(t, ics[0].Manager, ics[2].Manager)
|
||||||
assert.Equal(t, ics[0].Manager, ics[1].Manager)
|
assert.NotEqual(t, ics[0].UUID, ics[2].UUID)
|
||||||
assert.NotEqual(t, ics[0].UUID, ics[1].UUID)
|
assert.NotEqual(t, ics[0].ID, ics[2].ID)
|
||||||
assert.NotEqual(t, ics[0].ID, ics[1].ID)
|
|
||||||
|
assert.NotEqual(t, ics[0].Name, ics[1].Name)
|
||||||
|
assert.NotEqual(t, ics[0].Category, ics[1].Category)
|
||||||
|
assert.NotEqual(t, ics[0].Type, ics[1].Type)
|
||||||
|
|
||||||
|
// check associations between component configs and ICs
|
||||||
|
assert.Equal(t, configs[0].ICID, ics[0].ID)
|
||||||
|
assert.Equal(t, configs[1].ICID, ics[0].ID)
|
||||||
|
assert.Equal(t, configs[2].ICID, ics[1].ID)
|
||||||
|
assert.Equal(t, configs[3].ICID, ics[2].ID)
|
||||||
|
assert.Equal(t, configs[4].ICID, ics[2].ID)
|
||||||
|
assert.Equal(t, configs[5].ICID, ics[1].ID)
|
||||||
|
|
||||||
// compare original and duplicated dashboards
|
// compare original and duplicated dashboards
|
||||||
err = db.Order("created_at asc").Find(&dashboards).Error
|
err = db.Order("created_at asc").Find(&dashboards).Error
|
||||||
|
@ -1011,13 +1043,187 @@ func TestDuplicateScenarioForUser(t *testing.T) {
|
||||||
assert.NotEqual(t, dashboards[1].ScenarioID, dashboards[3].ScenarioID)
|
assert.NotEqual(t, dashboards[1].ScenarioID, dashboards[3].ScenarioID)
|
||||||
assert.NotEqual(t, dashboards[1].ID, dashboards[3].ID)
|
assert.NotEqual(t, dashboards[1].ID, dashboards[3].ID)
|
||||||
|
|
||||||
// compare original and duplicated widget
|
// compare original and duplicated widget (ICstatus)
|
||||||
var widgets []database.Widget
|
var widgets []database.Widget
|
||||||
err = db.Find(&widgets).Error
|
err = db.Find(&widgets).Error
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 2, len(widgets))
|
assert.Equal(t, 2, len(widgets))
|
||||||
assert.Equal(t, widgets[0].Name, widgets[1].Name)
|
assert.Equal(t, widgets[0].Name, widgets[1].Name)
|
||||||
assert.Equal(t, widgets[0].CustomProperties, widgets[1].CustomProperties)
|
assert.NotEqual(t, widgets[0].CustomProperties, widgets[1].CustomProperties)
|
||||||
|
assert.Equal(t, widgets[0].MinHeight, widgets[1].MinHeight)
|
||||||
|
assert.Equal(t, widgets[0].MinWidth, widgets[1].MinWidth)
|
||||||
|
assert.NotEqual(t, widgets[0].DashboardID, widgets[1].DashboardID)
|
||||||
|
assert.NotEqual(t, widgets[0].ID, widgets[1].ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScenarioDuplicationAlreadyDuplicatedIC(t *testing.T) {
|
||||||
|
/*
|
||||||
|
* Test: IC was already duplicated, exists in DB at the time of duplication
|
||||||
|
**/
|
||||||
|
database.DropTables()
|
||||||
|
database.MigrateModels()
|
||||||
|
assert.NoError(t, database.AddTestUsers())
|
||||||
|
|
||||||
|
// connect AMQP client
|
||||||
|
// Make sure that AMQP_HOST, AMQP_USER, AMQP_PASS are set
|
||||||
|
host, _ := configuration.GlobalConfig.String("amqp.host")
|
||||||
|
usr, _ := configuration.GlobalConfig.String("amqp.user")
|
||||||
|
pass, _ := configuration.GlobalConfig.String("amqp.pass")
|
||||||
|
amqpURI := "amqp://" + usr + ":" + pass + "@" + host
|
||||||
|
|
||||||
|
// AMQP Connection startup is tested here
|
||||||
|
// Not repeated in other tests because it is only needed once
|
||||||
|
session = helper.NewAMQPSession("villas-test-session", amqpURI, "villas", infrastructure_component.ProcessMessage)
|
||||||
|
SetAMQPSession(session)
|
||||||
|
infrastructure_component.SetAMQPSession(session)
|
||||||
|
|
||||||
|
// authenticate as admin (needed to create original IC)
|
||||||
|
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
/*** Create original scenario and entities ***/
|
||||||
|
scenarioID := addScenario(token)
|
||||||
|
var originalSo database.Scenario
|
||||||
|
db := database.GetDB()
|
||||||
|
err = db.Find(&originalSo, scenarioID).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// add file to scenario
|
||||||
|
fileID, err := addFile(scenarioID, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEqual(t, 99, fileID)
|
||||||
|
|
||||||
|
// add ICs (kubernetes simulator plus other)
|
||||||
|
err = addICs(session, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// add two component configs with the same IC (ID 1)
|
||||||
|
// plus one component config with IC != kubernetes simulator (ID 2)
|
||||||
|
err = addComponentConfigs(scenarioID, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* component/IC test setup:
|
||||||
|
* C0 --> IC0
|
||||||
|
* C1 --> IC0
|
||||||
|
* C2 --> IC1
|
||||||
|
* x --> IC2
|
||||||
|
* ---- after duplication: ----
|
||||||
|
* C3 --> IC2
|
||||||
|
* C4 --> IC2
|
||||||
|
* C5 --> IC1
|
||||||
|
*/
|
||||||
|
|
||||||
|
// add dashboards to scenario
|
||||||
|
err = addTwoDashboards(scenarioID, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
var dashboards []database.Dashboard
|
||||||
|
err = db.Find(&dashboards).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 2, len(dashboards))
|
||||||
|
|
||||||
|
// add widgets
|
||||||
|
dashboardID_forAddingWidget := uint(1)
|
||||||
|
err = addWidget(dashboardID_forAddingWidget, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
/*** Duplicate scenario for new user ***/
|
||||||
|
username := "Schnittlauch"
|
||||||
|
myUser, err := NewUser(username, "", "schnitti@lauch.de", "User", true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// add IC which will be seen as the duplicate IC
|
||||||
|
err = addDuplicateIC(token, username)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
log.Println("--------ICs before duplication ------------")
|
||||||
|
var icsqq []database.InfrastructureComponent
|
||||||
|
err = db.Order("created_at asc").Find(&icsqq).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 3, len(icsqq))
|
||||||
|
for _, ic := range icsqq {
|
||||||
|
log.Printf("IC (id/name): (%d/%s)", ic.ID, ic.Name)
|
||||||
|
}
|
||||||
|
log.Println("------------------")
|
||||||
|
|
||||||
|
duplicateScenarioForUser(originalSo, &myUser.User, "")
|
||||||
|
|
||||||
|
/*** Check duplicated scenario for correctness ***/
|
||||||
|
var dplScenarios []database.Scenario
|
||||||
|
err = db.Find(&dplScenarios, "name = ?", originalSo.Name+" "+username).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(dplScenarios))
|
||||||
|
assert.Equal(t, originalSo.StartParameters, dplScenarios[0].StartParameters)
|
||||||
|
|
||||||
|
// compare original and duplicated component configs
|
||||||
|
var configs []database.ComponentConfiguration
|
||||||
|
err = db.Find(&configs).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 6, len(configs))
|
||||||
|
assert.Equal(t, configs[0].Name, configs[3].Name)
|
||||||
|
assert.Equal(t, configs[0].FileIDs, configs[3].FileIDs)
|
||||||
|
assert.Equal(t, configs[0].InputMapping, configs[3].InputMapping)
|
||||||
|
assert.Equal(t, configs[0].OutputMapping, configs[3].OutputMapping)
|
||||||
|
assert.Equal(t, configs[0].StartParameters, configs[3].StartParameters)
|
||||||
|
assert.NotEqual(t, configs[0].ScenarioID, configs[3].ScenarioID)
|
||||||
|
assert.NotEqual(t, configs[0].ICID, configs[3].ICID) // original and duplicated IC
|
||||||
|
assert.NotEqual(t, configs[0].ID, configs[3].ID)
|
||||||
|
|
||||||
|
assert.Equal(t, configs[0].ScenarioID, configs[1].ScenarioID)
|
||||||
|
assert.Equal(t, configs[0].ScenarioID, configs[2].ScenarioID)
|
||||||
|
assert.Equal(t, configs[3].ScenarioID, configs[4].ScenarioID)
|
||||||
|
assert.Equal(t, configs[3].ScenarioID, configs[5].ScenarioID)
|
||||||
|
|
||||||
|
assert.Equal(t, configs[0].ICID, configs[1].ICID) // same IC for both configs
|
||||||
|
assert.Equal(t, configs[3].ICID, configs[4].ICID) // same duplicated IC
|
||||||
|
assert.Equal(t, configs[2].ICID, configs[5].ICID) // reused (not duplicated) IC
|
||||||
|
log.Println(configs[2].ICID)
|
||||||
|
log.Println(configs[5].ICID)
|
||||||
|
assert.NotEqual(t, configs[0].ICID, configs[2].ICID)
|
||||||
|
assert.NotEqual(t, configs[0].ICID, configs[3].ICID)
|
||||||
|
|
||||||
|
// compare original and duplicated infrastructure component
|
||||||
|
var ics []database.InfrastructureComponent
|
||||||
|
err = db.Order("created_at asc").Find(&ics).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 3, len(ics))
|
||||||
|
log.Println("--------ICs after duplication ------------")
|
||||||
|
|
||||||
|
for _, ic := range ics {
|
||||||
|
log.Printf("IC (id/name): (%d/%s)", ic.ID, ic.Name)
|
||||||
|
}
|
||||||
|
log.Println("------------------")
|
||||||
|
|
||||||
|
// check associations between component configs and ICs
|
||||||
|
assert.Equal(t, configs[0].ICID, ics[0].ID)
|
||||||
|
assert.Equal(t, configs[1].ICID, ics[0].ID)
|
||||||
|
assert.Equal(t, configs[2].ICID, ics[1].ID)
|
||||||
|
assert.Equal(t, configs[3].ICID, ics[2].ID)
|
||||||
|
assert.Equal(t, configs[4].ICID, ics[2].ID)
|
||||||
|
assert.Equal(t, configs[5].ICID, ics[1].ID)
|
||||||
|
|
||||||
|
// compare original and duplicated dashboards
|
||||||
|
err = db.Order("created_at asc").Find(&dashboards).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 4, len(dashboards))
|
||||||
|
assert.Equal(t, dashboards[0].Name, dashboards[2].Name)
|
||||||
|
assert.Equal(t, dashboards[0].Grid, dashboards[2].Grid)
|
||||||
|
assert.Equal(t, dashboards[0].Height, dashboards[2].Height)
|
||||||
|
assert.NotEqual(t, dashboards[0].ScenarioID, dashboards[2].ScenarioID)
|
||||||
|
assert.NotEqual(t, dashboards[0].ID, dashboards[2].ID)
|
||||||
|
|
||||||
|
assert.Equal(t, dashboards[1].Name, dashboards[3].Name)
|
||||||
|
assert.Equal(t, dashboards[1].Grid, dashboards[3].Grid)
|
||||||
|
assert.Equal(t, dashboards[1].Height, dashboards[3].Height)
|
||||||
|
assert.NotEqual(t, dashboards[1].ScenarioID, dashboards[3].ScenarioID)
|
||||||
|
assert.NotEqual(t, dashboards[1].ID, dashboards[3].ID)
|
||||||
|
|
||||||
|
// compare original and duplicated widget (ICstatus)
|
||||||
|
var widgets []database.Widget
|
||||||
|
err = db.Find(&widgets).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 2, len(widgets))
|
||||||
|
assert.Equal(t, widgets[0].Name, widgets[1].Name)
|
||||||
|
assert.NotEqual(t, widgets[0].CustomProperties, widgets[1].CustomProperties)
|
||||||
assert.Equal(t, widgets[0].MinHeight, widgets[1].MinHeight)
|
assert.Equal(t, widgets[0].MinHeight, widgets[1].MinHeight)
|
||||||
assert.Equal(t, widgets[0].MinWidth, widgets[1].MinWidth)
|
assert.Equal(t, widgets[0].MinWidth, widgets[1].MinWidth)
|
||||||
assert.NotEqual(t, widgets[0].DashboardID, widgets[1].DashboardID)
|
assert.NotEqual(t, widgets[0].DashboardID, widgets[1].DashboardID)
|
||||||
|
@ -1155,17 +1361,17 @@ func addWidget(dashboardID uint, token string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
newWidget := WidgetRequest{
|
newWidget := WidgetRequest{
|
||||||
Name: "My label",
|
Name: "IC Status",
|
||||||
Type: "Label",
|
Type: "ICstatus",
|
||||||
Width: 100,
|
Width: 100,
|
||||||
Height: 50,
|
Height: 100,
|
||||||
MinWidth: 40,
|
MinWidth: 0,
|
||||||
MinHeight: 80,
|
MinHeight: 0,
|
||||||
X: 10,
|
X: 10,
|
||||||
Y: 10,
|
Y: 10,
|
||||||
Z: 200,
|
Z: 200,
|
||||||
IsLocked: false,
|
IsLocked: false,
|
||||||
CustomProperties: postgres.Jsonb{RawMessage: json.RawMessage(`{"textSize" : "20", "fontColor" : "#4287f5", "fontColor_opacity": 1}`)},
|
CustomProperties: postgres.Jsonb{RawMessage: json.RawMessage(`{"checkedIDs" : [1]}`)},
|
||||||
SignalIDs: []int64{},
|
SignalIDs: []int64{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,29 +1383,29 @@ func addWidget(dashboardID uint, token string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTrue() *bool {
|
func newFalse() *bool {
|
||||||
b := true
|
b := false
|
||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
func addIC(session *helper.AMQPsession, token string) error {
|
type ICRequest struct {
|
||||||
type ICRequest struct {
|
UUID string `json:"uuid,omitempty"`
|
||||||
UUID string `json:"uuid,omitempty"`
|
WebsocketURL string `json:"websocketurl,omitempty"`
|
||||||
WebsocketURL string `json:"websocketurl,omitempty"`
|
APIURL string `json:"apiurl,omitempty"`
|
||||||
APIURL string `json:"apiurl,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Category string `json:"category,omitempty"`
|
||||||
Category string `json:"category,omitempty"`
|
State string `json:"state,omitempty"`
|
||||||
State string `json:"state,omitempty"`
|
Location string `json:"location,omitempty"`
|
||||||
Location string `json:"location,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Description string `json:"description,omitempty"`
|
StartParameterSchema postgres.Jsonb `json:"startparameterschema,omitempty"`
|
||||||
StartParameterSchema postgres.Jsonb `json:"startparameterschema,omitempty"`
|
CreateParameterSchema postgres.Jsonb `json:"createparameterschema,omitempty"`
|
||||||
CreateParameterSchema postgres.Jsonb `json:"createparameterschema,omitempty"`
|
ManagedExternally *bool `json:"managedexternally"`
|
||||||
ManagedExternally *bool `json:"managedexternally"`
|
Manager string `json:"manager,omitempty"`
|
||||||
Manager string `json:"manager,omitempty"`
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create IC
|
func addICs(session *helper.AMQPsession, token string) error {
|
||||||
|
// create ICs
|
||||||
var newIC = ICRequest{
|
var newIC = ICRequest{
|
||||||
UUID: "7be0322d-354e-431e-84bd-ae4c9633138b",
|
UUID: "7be0322d-354e-431e-84bd-ae4c9633138b",
|
||||||
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
||||||
|
@ -1212,7 +1418,23 @@ func addIC(session *helper.AMQPsession, token string) error {
|
||||||
Description: "A kubernetes simulator for testing purposes",
|
Description: "A kubernetes simulator for testing purposes",
|
||||||
StartParameterSchema: postgres.Jsonb{json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
StartParameterSchema: postgres.Jsonb{json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
||||||
CreateParameterSchema: postgres.Jsonb{json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
CreateParameterSchema: postgres.Jsonb{json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
||||||
ManagedExternally: newTrue(),
|
ManagedExternally: newFalse(),
|
||||||
|
Manager: "7be0322d-354e-431e-84bd-ae4c9633beef",
|
||||||
|
}
|
||||||
|
|
||||||
|
var newIC2 = ICRequest{
|
||||||
|
UUID: "7be0322d-354e-431e-84bd-ae4c9635558b",
|
||||||
|
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
||||||
|
APIURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/api/v2",
|
||||||
|
Type: "villas-node",
|
||||||
|
Name: "ACS Demo Signals",
|
||||||
|
Category: "gateway",
|
||||||
|
State: "idle",
|
||||||
|
Location: "k8s",
|
||||||
|
Description: "A signal generator for testing purposes",
|
||||||
|
StartParameterSchema: postgres.Jsonb{RawMessage: json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
||||||
|
CreateParameterSchema: postgres.Jsonb{RawMessage: json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
||||||
|
ManagedExternally: newFalse(),
|
||||||
Manager: "7be0322d-354e-431e-84bd-ae4c9633beef",
|
Manager: "7be0322d-354e-431e-84bd-ae4c9633beef",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,10 +1466,42 @@ func addIC(session *helper.AMQPsession, token string) error {
|
||||||
|
|
||||||
err = session.Send(payload, newIC.Manager)
|
err = session.Send(payload, newIC.Manager)
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/v2/ic", "POST", helper.KeyModels{"ic": newIC2})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func addComponentConfig(scenarioID uint, token string) error {
|
func addDuplicateIC(token string, username string) error {
|
||||||
|
|
||||||
|
// create IC
|
||||||
|
var newIC = ICRequest{
|
||||||
|
UUID: "7aaa322d-354e-431e-84bd-ae4c9633138b",
|
||||||
|
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
||||||
|
APIURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/api/v2",
|
||||||
|
Type: "kubernetes",
|
||||||
|
Name: "Kubernetes Simulator " + username,
|
||||||
|
Category: "simulator",
|
||||||
|
State: "idle",
|
||||||
|
Location: "k8s",
|
||||||
|
Description: "A kubernetes simulator for testing purposes",
|
||||||
|
StartParameterSchema: postgres.Jsonb{json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
||||||
|
CreateParameterSchema: postgres.Jsonb{json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
||||||
|
ManagedExternally: newFalse(),
|
||||||
|
Manager: "7be0322d-354e-431e-84bd-ae4c9633beef",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err := helper.TestEndpoint(router, token,
|
||||||
|
"/api/v2/ic", "POST", helper.KeyModels{"ic": newIC})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func addComponentConfigs(scenarioID uint, token string) error {
|
||||||
type ConfigRequest struct {
|
type ConfigRequest struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
ScenarioID uint `json:"scenarioID,omitempty"`
|
ScenarioID uint `json:"scenarioID,omitempty"`
|
||||||
|
@ -1264,8 +1518,36 @@ func addComponentConfig(scenarioID uint, token string) error {
|
||||||
FileIDs: []int64{},
|
FileIDs: []int64{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var newConfig2 = ConfigRequest{
|
||||||
|
Name: "Example for Signal generator",
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
ICID: 1,
|
||||||
|
StartParameters: postgres.Jsonb{RawMessage: json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)},
|
||||||
|
FileIDs: []int64{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var newConfig3 = ConfigRequest{
|
||||||
|
Name: "Example for Signal generator",
|
||||||
|
ScenarioID: scenarioID,
|
||||||
|
ICID: 2,
|
||||||
|
StartParameters: postgres.Jsonb{RawMessage: json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)},
|
||||||
|
FileIDs: []int64{},
|
||||||
|
}
|
||||||
|
|
||||||
_, _, err := helper.TestEndpoint(router, token,
|
_, _, err := helper.TestEndpoint(router, token,
|
||||||
"/api/v2/configs", "POST", helper.KeyModels{"config": newConfig1})
|
"/api/v2/configs", "POST", helper.KeyModels{"config": newConfig1})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/v2/configs", "POST", helper.KeyModels{"config": newConfig2})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = helper.TestEndpoint(router, token,
|
||||||
|
"/api/v2/configs", "POST", helper.KeyModels{"config": newConfig3})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue