From bd46d11155931fb3707f8a2a5e2e8a689075238e Mon Sep 17 00:00:00 2001 From: Repinoid Date: Tue, 22 Sep 2026 21:20:43 +0300 Subject: [PATCH] =?UTF-8?q?test(core,gen):=20unit-=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D1=8B=20modifierDesiredEqualsCurrent=20=D0=B8=20ValidateSpec?= =?UTF-8?q?=20modifier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../internal/loader/loader_modifier_test.go | 59 +++++++++++++++++ .../internal/core/modifier_compare_test.go | 63 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 TOOLS/resource-generator/internal/loader/loader_modifier_test.go create mode 100644 provider/internal/core/modifier_compare_test.go diff --git a/TOOLS/resource-generator/internal/loader/loader_modifier_test.go b/TOOLS/resource-generator/internal/loader/loader_modifier_test.go new file mode 100644 index 0000000..87a60ad --- /dev/null +++ b/TOOLS/resource-generator/internal/loader/loader_modifier_test.go @@ -0,0 +1,59 @@ +package loader + +import ( + "testing" + + "resource-generator/internal/types" + "tf-tools/lib" +) + +func TestValidateSpecModifier(t *testing.T) { + mkModifier := func(ds string, idem string, dps []lib.DeleteParam, params []lib.ParamSpec) *types.ServiceSpec { + return &types.ServiceSpec{ + Name: "vc_nsxt", + ServiceID: 22, + Operations: []lib.OperationSpec{ + { + Name: "modify", + ID: 111, + Kind: "modifier", + Action: "modify", + Modifier: "network", + DeleteStrategy: ds, + Idempotency: idem, + DeleteParams: dps, + Params: params, + }, + }, + } + } + + tests := []struct { + name string + spec *types.ServiceSpec + want bool // want error (true) or OK (false) + }{ + {"валидный inverse", mkModifier("inverse", "none", + []lib.DeleteParam{{Code: "needEnableAVI", Value: "false"}}, + []lib.ParamSpec{{Code: "needEnableAVI", Required: false}}), false}, + {"неизвестный delete_strategy", mkModifier("bogus", "none", nil, nil), true}, + {"inverse без delete_params", mkModifier("inverse", "none", nil, + []lib.ParamSpec{{Code: "needEnableAVI"}}), true}, + {"delete_params.code вне params", mkModifier("inverse", "none", + []lib.DeleteParam{{Code: "missing", Value: "false"}}, + []lib.ParamSpec{{Code: "needEnableAVI"}}), true}, + {"неизвестный idempotency", mkModifier("noop_warn", "bogus", nil, nil), true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := ValidateSpec("test.yaml", tt.spec) + if tt.want && err == nil { + t.Errorf("ожидали ошибку, получили nil") + } + if !tt.want && err != nil { + t.Errorf("ожидали OK, получили: %v", err) + } + }) + } +} diff --git a/provider/internal/core/modifier_compare_test.go b/provider/internal/core/modifier_compare_test.go new file mode 100644 index 0000000..0ec293b --- /dev/null +++ b/provider/internal/core/modifier_compare_test.go @@ -0,0 +1,63 @@ +package core + +import "testing" + +func TestModifierDesiredEqualsCurrent_Scalars(t *testing.T) { + c := &UniversalClient{} + cfsParams := []universalCfsParam{ + {SvcOperationCfsParamId: 340, Code: "needEnableAVI", DataType: "boolean", ParamValue: strPtr("false")}, + {SvcOperationCfsParamId: 369, Code: "virtualServicesCount", DataType: "integer > 0", ParamValue: strPtr("3")}, + {SvcOperationCfsParamId: 856, Code: "qosProfile", DataType: "string", ParamValue: strPtr("QoS-100Mbit")}, + } + + tests := []struct { + name string + desired map[string]string + want bool + }{ + {"все совпали", map[string]string{"needEnableAVI": "false", "virtualServicesCount": "3", "qosProfile": "QoS-100Mbit"}, true}, + {"bool расхождение", map[string]string{"needEnableAVI": "true"}, false}, + {"int расхождение", map[string]string{"virtualServicesCount": "1"}, false}, + {"нормализация пробела", map[string]string{"virtualServicesCount": " 3 "}, true}, + {"код не найден в схеме", map[string]string{"неизвестный": "x"}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := c.modifierDesiredEqualsCurrent(tt.desired, cfsParams); got != tt.want { + t.Errorf("modifierDesiredEqualsCurrent() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestModifierDesiredEqualsCurrent_MapFixed(t *testing.T) { + c := &UniversalClient{} + // map-fixed: порядок ключей не значим + cfsParams := []universalCfsParam{ + {SvcOperationCfsParamId: 1112, Code: "routedNetConfiguration", DataType: "map-fixed", + ParamValue: strPtr(`{"ipAddrPool":"10.10.102.0/24","mainDns":"81.22.46.22"}`)}, + } + desired := map[string]string{ + "routedNetConfiguration": `{"mainDns":"81.22.46.22","ipAddrPool":"10.10.102.0/24"}`, + } + if !c.modifierDesiredEqualsCurrent(desired, cfsParams) { + t.Errorf("map-fixed с разным порядком ключей должен считаться равным") + } +} + +func TestModifierDesiredEqualsCurrent_ArrayPreservesOrder(t *testing.T) { + c := &UniversalClient{} + // array-map-fixed: порядок элементов массива значим + cfsParams := []universalCfsParam{ + {SvcOperationCfsParamId: 662, Code: "vIPConfigure", DataType: "array-map-fixed", + ParamValue: strPtr(`[{"name":"a","count":1},{"name":"b","count":2}]`)}, + } + // тот же порядок — равно + if !c.modifierDesiredEqualsCurrent(map[string]string{"vIPConfigure": `[{"name":"a","count":1},{"name":"b","count":2}]`}, cfsParams) { + t.Errorf("array-map-fixed с тем же порядком должен быть равен") + } + // другой порядок — не равно + if c.modifierDesiredEqualsCurrent(map[string]string{"vIPConfigure": `[{"name":"b","count":2},{"name":"a","count":1}]`}, cfsParams) { + t.Errorf("array-map-fixed с другим порядком не должен быть равен") + } +}