From 276764e54ba44e07cd80774bffc03c465b9d42b3 Mon Sep 17 00:00:00 2001 From: Helder Betiol <37706737+helderbetiol@users.noreply.github.com> Date: Fri, 12 Jul 2024 16:54:16 +0200 Subject: [PATCH] Refactor(cli) ApplyTemplate (#497) * refactor(cli) applytemplate * fix(cli) tests * fix(cli) simplified fbx template apply --- CLI/controllers/template.go | 80 +--------------------------- CLI/controllers/template_test.go | 21 +++++++- CLI/controllers/utils.go | 10 ---- CLI/models/attributes.go | 54 +++++++++++++++++++ CLI/models/attributes_device.go | 14 +++++ CLI/models/attributes_device_test.go | 16 ++++++ CLI/models/attributes_room.go | 21 ++++++++ 7 files changed, 127 insertions(+), 89 deletions(-) diff --git a/CLI/controllers/template.go b/CLI/controllers/template.go index b51ce51d..6d7b209a 100644 --- a/CLI/controllers/template.go +++ b/CLI/controllers/template.go @@ -2,7 +2,6 @@ package controllers import ( "cli/models" - "cli/utils" "errors" "fmt" "net/http" @@ -79,83 +78,8 @@ func (controller Controller) ApplyTemplate(attr, data map[string]interface{}, en return err } - key := determineStrKey(tmpl, []string{"sizeWDHmm", "sizeWDHm"}) - - if sizeInf, hasSize := tmpl[key].([]any); hasSize && len(sizeInf) == 3 { - attr["size"] = sizeInf[:2] - attr["height"] = sizeInf[2] - utils.CopyMapVal(attr, tmpl, "shape") - - if ent == models.DEVICE { - if tmpx, ok := tmpl["attributes"]; ok { - if x, ok := tmpx.(map[string]interface{}); ok { - if tmp, ok := x["type"]; ok { - if t, ok := tmp.(string); ok { - if t == "chassis" || t == "server" { - res := 0 - if val, ok := sizeInf[2].(float64); ok { - res = int((val / 1000) / models.RACKUNIT) - } else if val, ok := sizeInf[2].(int); ok { - res = int((float64(val) / 1000) / models.RACKUNIT) - } else { - return errors.New("invalid size vector on given template") - } - attr["sizeU"] = res - } - } - } - } - } - - } else if ent == models.ROOM { - //Copy additional Room specific attributes - utils.CopyMapVal(attr, tmpl, "technicalArea") - if _, ok := attr["technicalArea"]; ok { - attr["technical"] = attr["technicalArea"] - delete(attr, "technicalArea") - } - - utils.CopyMapVal(attr, tmpl, "reservedArea") - if _, ok := attr["reservedArea"]; ok { - attr["reserved"] = attr["reservedArea"] - delete(attr, "reservedArea") - } - - for _, attrName := range []string{"axisOrientation", "separators", - "pillars", "floorUnit", "tiles", "rows", "aisles", - "vertices", "colors", "tileAngle"} { - utils.CopyMapVal(attr, tmpl, attrName) - } - - } else { - attr["sizeUnit"] = "mm" - attr["heightUnit"] = "mm" - } - - //Copy Description - if _, ok := tmpl["description"]; ok { - data["description"] = tmpl["description"] - } - - //fbxModel section - if check := utils.CopyMapVal(attr, tmpl, "fbxModel"); !check { - if ent != models.BLDG { - attr["fbxModel"] = "" - } - } - - //Copy orientation if available - utils.CopyMapVal(attr, tmpl, "orientation") - - //Merge attributes if available - if tmplAttrsInf, ok := tmpl["attributes"]; ok { - if tmplAttrs, ok := tmplAttrsInf.(map[string]interface{}); ok { - utils.MergeMaps(attr, tmplAttrs, false) - } - } - } else { - println("Warning, invalid size value in template.") - return errors.New("invalid size vector on given template") + if err := models.ApplyTemplateToObj(attr, data, tmpl, ent); err != nil { + return err } return nil diff --git a/CLI/controllers/template_test.go b/CLI/controllers/template_test.go index 61b38c1c..c64a9b23 100644 --- a/CLI/controllers/template_test.go +++ b/CLI/controllers/template_test.go @@ -64,7 +64,7 @@ func TestApplyTemplateOfTypeDeviceError(t *testing.T) { } device["attributes"] = attributes template := test_utils.GetEntity("deviceChasisTemplate", "device-template", "", "") - template["sizeWDHmm"] = []any{216, 659, "100"} + template["sizeWDHmm"] = []any{216, 659} test_utils.MockGetObjTemplate(mockAPI, template) @@ -74,6 +74,25 @@ func TestApplyTemplateOfTypeDeviceError(t *testing.T) { assert.Equal(t, "invalid size vector on given template", err.Error()) } +func TestApplyTemplateOfTypeDeviceConvertError(t *testing.T) { + controller, mockAPI, _ := layersSetup(t) + + device := test_utils.CopyMap(chassis) + attributes := map[string]any{ + "template": "device-template", + } + device["attributes"] = attributes + template := test_utils.GetEntity("deviceChasisTemplate", "device-template", "", "") + template["sizeWDHmm"] = []any{216, 659, "100"} + + test_utils.MockGetObjTemplate(mockAPI, template) + + err := controller.ApplyTemplate(attributes, device, models.DEVICE) + assert.NotNil(t, err) + + assert.Equal(t, "cannot convert string to float64", err.Error()) +} + func TestApplyTemplateOfTypeRoomWorks(t *testing.T) { controller, mockAPI, _ := layersSetup(t) diff --git a/CLI/controllers/utils.go b/CLI/controllers/utils.go index dd7d137d..d0a846c6 100644 --- a/CLI/controllers/utils.go +++ b/CLI/controllers/utils.go @@ -49,13 +49,3 @@ type ErrorWithInternalError struct { func (err ErrorWithInternalError) Error() string { return err.UserError.Error() + " caused by " + err.InternalError.Error() } - -// Utility functions -func determineStrKey(x map[string]interface{}, possible []string) string { - for idx := range possible { - if _, ok := x[possible[idx]]; ok { - return possible[idx] - } - } - return "" //The code should not reach this point! -} diff --git a/CLI/models/attributes.go b/CLI/models/attributes.go index fd0dc2a7..9cb827cd 100644 --- a/CLI/models/attributes.go +++ b/CLI/models/attributes.go @@ -5,6 +5,8 @@ package models import ( l "cli/logger" + "cli/utils" + "errors" "fmt" "strconv" "strings" @@ -222,6 +224,58 @@ func SetRoomAreas(values []any) (map[string]any, error) { } } +func ApplyTemplateToObj(attr, data, tmpl map[string]any, ent int) error { + // Copy size + key := determineStrKey(tmpl, []string{"sizeWDHmm", "sizeWDHm"}) + sizeInf, hasSize := tmpl[key].([]any) + if !hasSize || len(sizeInf) != 3 { + return errors.New("invalid size vector on given template") + } + attr["size"] = sizeInf[:2] + attr["height"] = sizeInf[2] + if ent == DEVICE { + if err := SetDeviceSizeUFromTemplate(attr, tmpl, sizeInf[2]); err != nil { + return err + } + } else if ent == ROOM { + ApplyRoomTemplateAttributes(attr, tmpl) + } else { + attr["sizeUnit"] = "mm" + attr["heightUnit"] = "mm" + } + + // Copy description + if _, ok := tmpl["description"]; ok { + data["description"] = tmpl["description"] + } + + // fbxModel section + if ent != BLDG && ent != ROOM { + utils.CopyMapVal(attr, tmpl, "fbxModel") + } + + // Copy orientation and shape if available + utils.CopyMapVal(attr, tmpl, "orientation") + utils.CopyMapVal(attr, tmpl, "shape") + + // Merge attributes if available + if tmplAttrs, ok := tmpl["attributes"].(map[string]any); ok { + utils.MergeMaps(attr, tmplAttrs, false) + } + + return nil +} + +// Helpers +func determineStrKey(x map[string]interface{}, possible []string) string { + for idx := range possible { + if _, ok := x[possible[idx]]; ok { + return possible[idx] + } + } + return "" //The code should not reach this point! +} + // errResponder helper func for specialUpdateNode // used for separator, pillar err msgs and validateRoomAreas() func ErrorResponder(attr, numElts string, multi bool) error { diff --git a/CLI/models/attributes_device.go b/CLI/models/attributes_device.go index 7ccd9e72..ba8f9344 100644 --- a/CLI/models/attributes_device.go +++ b/CLI/models/attributes_device.go @@ -53,3 +53,17 @@ func ComputeSizeUAndHeight(obj, data map[string]any) error { } return nil } + +func SetDeviceSizeUFromTemplate(deviceAttrs, tmpl map[string]any, tmplHeight any) error { + if tmplAttrs, ok := tmpl["attributes"].(map[string]any); ok { + if tmplType, ok := tmplAttrs["type"].(string); ok && + (tmplType == "chassis" || tmplType == "server") { + if height, err := utils.GetFloat(tmplHeight); err != nil { + return err + } else { + deviceAttrs["sizeU"] = int((height / 1000) / RACKUNIT) + } + } + } + return nil +} diff --git a/CLI/models/attributes_device_test.go b/CLI/models/attributes_device_test.go index 79016687..1b75577e 100644 --- a/CLI/models/attributes_device_test.go +++ b/CLI/models/attributes_device_test.go @@ -110,3 +110,19 @@ func TestComputeFromHeightFail(t *testing.T) { } // endregion + +// region template + +func TestSetDeviceSizeUFromTemplateWorks(t *testing.T) { + deviceAttrs := map[string]any{} + input := map[string]any{ + "attributes": map[string]any{ + "type": "chassis", + }, + } + err := models.SetDeviceSizeUFromTemplate(deviceAttrs, input, any(10000)) + assert.Nil(t, err) + assert.Equal(t, 224, deviceAttrs["sizeU"]) +} + +// endregion diff --git a/CLI/models/attributes_room.go b/CLI/models/attributes_room.go index 1939d63e..5a9153d6 100644 --- a/CLI/models/attributes_room.go +++ b/CLI/models/attributes_room.go @@ -63,3 +63,24 @@ func ValuesToSeparator(values []any) (string, Separator, error) { } return name, Separator{startPos, endPos, sepType}, nil } + +func ApplyRoomTemplateAttributes(attr, tmpl map[string]any) { + //Copy Room specific attributes + utils.CopyMapVal(attr, tmpl, "technicalArea") + if _, ok := attr["technicalArea"]; ok { + attr["technical"] = attr["technicalArea"] + delete(attr, "technicalArea") + } + + utils.CopyMapVal(attr, tmpl, "reservedArea") + if _, ok := attr["reservedArea"]; ok { + attr["reserved"] = attr["reservedArea"] + delete(attr, "reservedArea") + } + + for _, attrName := range []string{"axisOrientation", "separators", + "pillars", "floorUnit", "tiles", "rows", "aisles", + "vertices", "colors", "tileAngle"} { + utils.CopyMapVal(attr, tmpl, attrName) + } +}