From 71919ae0c3fd6f7d09eeb3c2fd7300c1f3c60d4d Mon Sep 17 00:00:00 2001 From: wenqi Date: Tue, 19 Nov 2024 17:55:58 +0800 Subject: [PATCH] Improve unit-test for subnet service (#850) Unit test coverage increased by 3%, reaching 73.07%. Signed-off-by: Wenqi Qiu --- Makefile | 2 +- codecov.yaml | 6 + .../subnetset/subnetset_controller_test.go | 123 ++++++---- pkg/nsx/services/subnet/builder.go | 6 +- pkg/nsx/services/subnet/subnet.go | 2 +- pkg/nsx/services/subnet/subnet_test.go | 220 ++++++++++++++---- 6 files changed, 267 insertions(+), 92 deletions(-) diff --git a/Makefile b/Makefile index 7f21e48cf..584299ff5 100644 --- a/Makefile +++ b/Makefile @@ -79,7 +79,7 @@ golangci-fix: $(GOLANGCI_LINT_BIN) .PHONY: test test: manifests generate fmt vet envtest .coverage ## Run tests . - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -gcflags=all=-l $$(go list ./... | grep -v mock | grep -v e2e | grep -v hack) -v -coverprofile $(CURDIR)/.coverage/coverage-unit.out ## Prohibit inline optimization when using gomonkey + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -gcflags=all=-l -coverpkg=github.com/vmware-tanzu/nsx-operator/pkg/...,github.com/vmware-tanzu/nsx-operator/cmd/... -covermode=atomic $$(go list ./... | grep -v mock | grep -v e2e | grep -v hack) -v -coverprofile $(CURDIR)/.coverage/coverage-unit.out ## Prohibit inline optimization when using gomonkey ##@ Build diff --git a/codecov.yaml b/codecov.yaml index e20b583e0..1050bd522 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -33,3 +33,9 @@ flag_management: ignore: - "**/test/*.go" + - "**/mock_*.go" + - "**/*generate*.go" + - "pkg/client" + - "pkg/mock" + - "**/pkg/client" + - "**/*.pb.go" diff --git a/pkg/controllers/subnetset/subnetset_controller_test.go b/pkg/controllers/subnetset/subnetset_controller_test.go index f9375c878..4dd1266ee 100644 --- a/pkg/controllers/subnetset/subnetset_controller_test.go +++ b/pkg/controllers/subnetset/subnetset_controller_test.go @@ -36,6 +36,7 @@ import ( "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnet" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/subnetport" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/vpc" + "github.com/vmware-tanzu/nsx-operator/pkg/util" ) type fakeRecorder struct{} @@ -49,6 +50,38 @@ func (recorder fakeRecorder) Eventf(object runtime.Object, eventtype, reason, me func (recorder fakeRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) { } +type fakeOrgRootClient struct { +} + +func (f fakeOrgRootClient) Get(basePathParam *string, filterParam *string, typeFilterParam *string) (model.OrgRoot, error) { + return model.OrgRoot{}, nil +} + +func (f fakeOrgRootClient) Patch(orgRootParam model.OrgRoot, enforceRevisionCheckParam *bool) error { + return errors.New("patch error") +} + +type fakeSubnetStatusClient struct { +} + +func (f fakeSubnetStatusClient) List(orgIdParam string, projectIdParam string, vpcIdParam string, subnetIdParam string) (model.VpcSubnetStatusListResult, error) { + dhcpServerAddress := "1.1.1.1" + ipAddressType := "fakeIpAddressType" + networkAddress := "2.2.2.2" + gatewayAddress := "3.3.3.3" + return model.VpcSubnetStatusListResult{ + Results: []model.VpcSubnetStatus{ + { + DhcpServerAddress: &gatewayAddress, + GatewayAddress: &dhcpServerAddress, + IpAddressType: &ipAddressType, + NetworkAddress: &networkAddress, + }, + }, + Status: nil, + }, nil +} + func createFakeSubnetSetReconciler(objs []client.Object) *SubnetSetReconciler { newScheme := runtime.NewScheme() utilruntime.Must(clientgoscheme.AddToScheme(newScheme)) @@ -62,10 +95,15 @@ func createFakeSubnetSetReconciler(objs []client.Object) *SubnetSetReconciler { } subnetService := &subnet.SubnetService{ Service: common.Service{ - Client: fakeClient, - NSXClient: &nsx.Client{}, - + Client: fakeClient, + NSXClient: &nsx.Client{ + OrgRootClient: &fakeOrgRootClient{}, + SubnetStatusClient: &fakeSubnetStatusClient{}, + }, NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: "clusterName", + }, NsxConfig: &config.NsxConfig{ EnforcementPoint: "vmc-enforcementpoint", UseAVILoadBalancer: false, @@ -97,6 +135,13 @@ func createFakeSubnetSetReconciler(objs []client.Object) *SubnetSetReconciler { func TestReconcile(t *testing.T) { subnetsetName := "test-subnetset" ns := "test-namespace" + subnetSet := &v1alpha1.SubnetSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: subnetsetName, + Namespace: ns, + }, + Spec: v1alpha1.SubnetSetSpec{}, + } testCases := []struct { name string @@ -124,9 +169,8 @@ func TestReconcile(t *testing.T) { }, }, { - name: "Create a SubnetSet with error failed to generate SubnetSet tags", - expectRes: ResultRequeue, - expectErrStr: "failed to generate SubnetSet tags", + name: "Create a SubnetSet", + expectRes: ResultNormal, patches: func(r *SubnetSetReconciler) *gomonkey.Patches { vpcnetworkInfo := &common.VPCNetworkConfigInfo{DefaultSubnetSize: 32} patches := gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "GetVPCNetworkConfigByNamespace", func(_ *vpc.VPCService, ns string) *common.VPCNetworkConfigInfo { @@ -211,22 +255,26 @@ func TestReconcile(t *testing.T) { patches := gomonkey.ApplyMethod(reflect.TypeOf(r.VPCService), "GetVPCNetworkConfigByNamespace", func(_ *vpc.VPCService, ns string) *common.VPCNetworkConfigInfo { return vpcnetworkInfo }) - patches.ApplyMethod(reflect.TypeOf(r.SubnetService.SubnetStore), "GetByIndex", func(_ *subnet.SubnetStore, key string, value string) []*model.VpcSubnet { id1 := "fake-id" - path := "fake-path" - vpcSubnet := model.VpcSubnet{Id: &id1, Path: &path} - return []*model.VpcSubnet{ - &vpcSubnet, - } - }) - - tags := []model.Tag{{Scope: common.String(common.TagScopeSubnetCRUID), Tag: common.String("fake-tag")}} - patches.ApplyMethod(reflect.TypeOf(r.SubnetService), "GenerateSubnetNSTags", func(_ *subnet.SubnetService, obj client.Object) []model.Tag { - return tags + path := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-e2e_8f36f7fc-90cd-4e65-a816-daf3ecd6a0f9/subnets/fake-path" + basicTags1 := util.BuildBasicTags("fakeClusterName", subnetSet, "") + scopeNamespace := common.TagScopeNamespace + basicTags1 = append(basicTags1, model.Tag{ + Scope: &scopeNamespace, + Tag: &ns, + }) + basicTags2 := util.BuildBasicTags("fakeClusterName", subnetSet, "") + ns2 := "ns2" + basicTags2 = append(basicTags2, model.Tag{ + Scope: &scopeNamespace, + Tag: &ns2, + }) + vpcSubnet1 := model.VpcSubnet{Id: &id1, Path: &path} + vpcSubnet2 := model.VpcSubnet{Id: &id1, Path: &path, Tags: basicTags1} + vpcSubnet3 := model.VpcSubnet{Id: &id1, Path: &path, Tags: basicTags2} + return []*model.VpcSubnet{&vpcSubnet1, &vpcSubnet2, &vpcSubnet3} }) - - // UpdateSubnetSet patches.ApplyMethod(reflect.TypeOf(r.SubnetService), "UpdateSubnetSet", func(_ *subnet.SubnetService, ns string, vpcSubnets []*model.VpcSubnet, tags []model.Tag, dhcpMode string) error { return nil }) @@ -239,18 +287,9 @@ func TestReconcile(t *testing.T) { ctx := context.TODO() req := ctrl.Request{NamespacedName: types.NamespacedName{Name: subnetsetName, Namespace: ns}} - subnetset := &v1alpha1.SubnetSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: subnetsetName, - Namespace: ns, - }, - Spec: v1alpha1.SubnetSetSpec{}, - } - namespace := &v12.Namespace{ - ObjectMeta: metav1.ObjectMeta{Name: ns, Namespace: ns}, - } + namespace := &v12.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} - r := createFakeSubnetSetReconciler([]client.Object{subnetset, namespace}) + r := createFakeSubnetSetReconciler([]client.Object{subnetSet, namespace}) if testCase.patches != nil { patches := testCase.patches(r) defer patches.Reset() @@ -260,6 +299,8 @@ func TestReconcile(t *testing.T) { if testCase.expectErrStr != "" { assert.ErrorContains(t, err, testCase.expectErrStr) + } else { + assert.NoError(t, err) } assert.Equal(t, testCase.expectRes, res) }) @@ -295,7 +336,7 @@ func TestReconcile_DeleteSubnetSet(t *testing.T) { vpcSubnetSkip := model.VpcSubnet{Id: &id1, Path: &path, Tags: tags} id2 := "fake-id-1" - path2 := "fake-path-2" + path2 := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-xxx/subnets/" + id2 tagStale := []model.Tag{ {Scope: common.String(common.TagScopeSubnetSetCRUID), Tag: common.String("fake-subnetSet-uid-stale")}, {Scope: common.String(common.TagScopeSubnetSetCRName), Tag: common.String(subnetSetName)}, @@ -330,7 +371,7 @@ func TestReconcile_DeleteSubnetSet(t *testing.T) { vpcSubnetSkip := model.VpcSubnet{Id: &id1, Path: &path, Tags: tags} id2 := "fake-id-1" - path2 := "fake-path-2" + path2 := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-xxx/subnets/fake-path-2" tagStale := []model.Tag{ {Scope: common.String(common.TagScopeSubnetSetCRUID), Tag: common.String("fake-subnetSet-uid-stale")}, {Scope: common.String(common.TagScopeSubnetSetCRName), Tag: common.String(subnetSetName)}, @@ -374,7 +415,7 @@ func TestReconcile_DeleteSubnetSet(t *testing.T) { vpcSubnetSkip := model.VpcSubnet{Id: &id1, Path: &path, Tags: tags} id2 := "fake-id-1" - path2 := "fake-path-2" + path2 := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-xxx/subnets/fake-path-2" tagStale := []model.Tag{ {Scope: common.String(common.TagScopeSubnetSetCRUID), Tag: common.String("fake-subnetSet-uid-stale")}, {Scope: common.String(common.TagScopeSubnetSetCRName), Tag: common.String(subnetSetName)}, @@ -443,7 +484,7 @@ func TestReconcile_DeleteSubnetSet_WithFinalizer(t *testing.T) { patches := gomonkey.ApplyMethod(reflect.TypeOf(r.SubnetService.SubnetStore), "GetByIndex", func(_ *subnet.SubnetStore, key string, value string) []*model.VpcSubnet { id1 := "fake-id" - path := "fake-path" + path := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-e2e_8f36f7fc-90cd-4e65-a816-daf3ecd6a0f9/subnets/" + id1 vpcSubnet := model.VpcSubnet{Id: &id1, Path: &path} return []*model.VpcSubnet{ &vpcSubnet, @@ -533,10 +574,10 @@ func TestSubnetSetReconciler_CollectGarbage(t *testing.T) { patches.ApplyMethod(reflect.TypeOf(r.SubnetService.SubnetStore), "GetByIndex", func(_ *subnet.SubnetStore, key string, value string) []*model.VpcSubnet { id1 := "fake-id" - path := "fake-path" - vpcSubnet := model.VpcSubnet{Id: &id1, Path: &path} + path := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-e2e_8f36f7fc-90cd-4e65-a816-daf3ecd6a0f9/subnets/fake-path" + vpcSubnet1 := model.VpcSubnet{Id: &id1, Path: &path} return []*model.VpcSubnet{ - &vpcSubnet, + &vpcSubnet1, } }) patches.ApplyMethod(reflect.TypeOf(r.SubnetPortService), "GetPortsOfSubnet", func(_ *subnetport.SubnetPortService, _ string) (ports []*model.VpcSubnetPort) { @@ -553,10 +594,12 @@ func TestSubnetSetReconciler_CollectGarbage(t *testing.T) { // ListSubnetCreatedBySubnetSet patches.ApplyMethod(reflect.TypeOf(r.SubnetService), "ListSubnetCreatedBySubnetSet", func(_ *subnet.SubnetService, id string) []*model.VpcSubnet { id1 := "fake-id" - path := "fake-path" - vpcSubnet := model.VpcSubnet{Id: &id1, Path: &path} + path := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-e2e_8f36f7fc-90cd-4e65-a816-daf3ecd6a0f9/subnets/fake-path" + vpcSubnet1 := model.VpcSubnet{Id: &id1, Path: &path} + invalidPath := "fakePath" + vpcSubnet2 := model.VpcSubnet{Id: &id1, Path: &invalidPath} return []*model.VpcSubnet{ - &vpcSubnet, + &vpcSubnet1, &vpcSubnet2, } }) diff --git a/pkg/nsx/services/subnet/builder.go b/pkg/nsx/services/subnet/builder.go index 7bd5bb014..f440aa984 100644 --- a/pkg/nsx/services/subnet/builder.go +++ b/pkg/nsx/services/subnet/builder.go @@ -60,7 +60,7 @@ func (service *SubnetService) buildSubnet(obj client.Object, tags []model.Tag, u var staticIpAllocation bool switch o := obj.(type) { case *v1alpha1.Subnet: - staticIpAllocation = (o.Spec.SubnetDHCPConfig.Mode == "" || o.Spec.SubnetDHCPConfig.Mode == v1alpha1.DHCPConfigMode(v1alpha1.DHCPConfigModeDeactivated)) + staticIpAllocation = o.Spec.SubnetDHCPConfig.Mode == "" || o.Spec.SubnetDHCPConfig.Mode == v1alpha1.DHCPConfigMode(v1alpha1.DHCPConfigModeDeactivated) nsxSubnet = &model.VpcSubnet{ Id: String(service.BuildSubnetID(o)), AccessMode: String(convertAccessMode(util.Capitalize(string(o.Spec.AccessMode)))), @@ -80,7 +80,7 @@ func (service *SubnetService) buildSubnet(obj client.Object, tags []model.Tag, u case *v1alpha1.SubnetSet: // The index is a random string with the length of 8 chars. It is the first 8 chars of the hash // value on a random UUID string. - staticIpAllocation = (o.Spec.SubnetDHCPConfig.Mode == "" || o.Spec.SubnetDHCPConfig.Mode == v1alpha1.DHCPConfigMode(v1alpha1.DHCPConfigModeDeactivated)) + staticIpAllocation = o.Spec.SubnetDHCPConfig.Mode == "" || o.Spec.SubnetDHCPConfig.Mode == v1alpha1.DHCPConfigMode(v1alpha1.DHCPConfigModeDeactivated) index := util.GetRandomIndexString() nsxSubnet = &model.VpcSubnet{ Id: String(service.buildSubnetSetID(o, index)), @@ -124,7 +124,7 @@ func (service *SubnetService) buildDHCPConfig(enableDHCP bool) *model.VpcSubnetD } func (service *SubnetService) buildSubnetDHCPConfig(mode string) *model.SubnetDhcpConfig { - // Trasfer DHCPDeactivated to DHCP_DEACTIVATED + // Transfer DHCPDeactivated to DHCP_DEACTIVATED nsxMode := strings.ToUpper(mode) nsxMode = nsxMode[:4] + "_" + nsxMode[4:] diff --git a/pkg/nsx/services/subnet/subnet.go b/pkg/nsx/services/subnet/subnet.go index 8d0d864b5..0b8cc101a 100644 --- a/pkg/nsx/services/subnet/subnet.go +++ b/pkg/nsx/services/subnet/subnet.go @@ -411,7 +411,7 @@ func (service *SubnetService) UpdateSubnetSet(ns string, vpcSubnets []*model.Vpc if dhcpMode == "" { dhcpMode = v1alpha1.DHCPConfigModeDeactivated } - staticIpAllocation := (dhcpMode == v1alpha1.DHCPConfigModeDeactivated) + staticIpAllocation := dhcpMode == v1alpha1.DHCPConfigModeDeactivated for i, vpcSubnet := range vpcSubnets { subnetSet := &v1alpha1.SubnetSet{} var name string diff --git a/pkg/nsx/services/subnet/subnet_test.go b/pkg/nsx/services/subnet/subnet_test.go index c2c83fcef..60f4b808a 100644 --- a/pkg/nsx/services/subnet/subnet_test.go +++ b/pkg/nsx/services/subnet/subnet_test.go @@ -2,15 +2,18 @@ package subnet import ( "context" + "reflect" "testing" "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/cache" @@ -22,6 +25,7 @@ import ( mock_client "github.com/vmware-tanzu/nsx-operator/pkg/mock/controller-runtime/client" "github.com/vmware-tanzu/nsx-operator/pkg/nsx" "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" + "github.com/vmware-tanzu/nsx-operator/pkg/util" ) func TestGenerateSubnetNSTags(t *testing.T) { @@ -115,12 +119,8 @@ func (f fakeSubnetsClient) Delete(orgIdParam string, projectIdParam string, vpcI return nil } -var fakeSubnetPath = "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-e2e_8f36f7fc-90cd-4e65-a816-daf3ecd6a0f9/subnets/subnet-1" -var fakeSubnetID = "fakeSubnetID" -var fakeVpcSubnet = model.VpcSubnet{Path: &fakeSubnetPath, Id: &fakeSubnetID} - func (f fakeSubnetsClient) Get(orgIdParam string, projectIdParam string, vpcIdParam string, subnetIdParam string) (model.VpcSubnet, error) { - return fakeVpcSubnet, nil + return model.VpcSubnet{}, nil } func (f fakeSubnetsClient) List(orgIdParam string, projectIdParam string, vpcIdParam string, cursorParam *string, includeMarkForDeleteObjectsParam *bool, includedFieldsParam *string, pageSizeParam *int64, sortAscendingParam *bool, sortByParam *string) (model.VpcSubnetListResult, error) { @@ -151,44 +151,17 @@ func (f fakeRealizedEntitiesClient) List(orgIdParam string, projectIdParam strin } func TestInitializeSubnetService(t *testing.T) { - newScheme := runtime.NewScheme() - utilruntime.Must(clientgoscheme.AddToScheme(newScheme)) - utilruntime.Must(v1alpha1.AddToScheme(newScheme)) - fakeClient := fake.NewClientBuilder().WithScheme(newScheme).Build() - // SubnetsClient - commonService := common.Service{ - Client: fakeClient, - NSXClient: &nsx.Client{ - OrgRootClient: &fakeOrgRootClient{}, - SubnetsClient: &fakeSubnetsClient{}, - QueryClient: &fakeQueryClient{}, - RealizedEntitiesClient: &fakeRealizedEntitiesClient{}, - // VPCClient: mockVpcclient, - // RestConnector: rc, - NsxConfig: &config.NSXOperatorConfig{ - CoeConfig: &config.CoeConfig{ - Cluster: "k8scl-one:test", - }, - }, - }, - NSXConfig: &config.NSXOperatorConfig{ - CoeConfig: &config.CoeConfig{ - Cluster: "k8scl-one:test", - }, - }, - } - service, err := InitializeSubnetService(commonService) - assert.NoError(t, err) - res := service.ListAllSubnet() - assert.Equal(t, 0, len(res)) - - subnetCR := &v1alpha1.Subnet{ + clusterName := "k8scl-one:test" + subnetID := "fakeSubnetUID" + subnetName := "fakeSubnetName" + nsName := "fakeNamespaceName" + subnet := &v1alpha1.Subnet{ TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, + ObjectMeta: metav1.ObjectMeta{UID: types.UID(subnetID), Name: subnetName, Namespace: nsName}, Spec: v1alpha1.SubnetSpec{}, Status: v1alpha1.SubnetStatus{}, } - vpcInfo := common.VPCResourceInfo{ + vpcResourceInfo := &common.VPCResourceInfo{ OrgID: "", ProjectID: "", VPCID: "", @@ -196,19 +169,172 @@ func TestInitializeSubnetService(t *testing.T) { ParentID: "", PrivateIpv4Blocks: nil, } - tags := []model.Tag{{}} - nsxSubnet, err := service.CreateOrUpdateSubnet(subnetCR, vpcInfo, tags) - assert.NoError(t, err) - assert.Equal(t, nsxSubnet, nsxSubnet) + nsxSubnetID := util.GenerateIDByObject(subnet) + + basicTags := util.BuildBasicTags(clusterName, subnet, "") + fakeSubnetPath := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-e2e_8f36f7fc-90cd-4e65-a816-daf3ecd6a0f9/subnets/" + nsxSubnetID + + testCases := []struct { + name string + prepareFunc func() *gomonkey.Patches + existingSubnetCR *v1alpha1.Subnet + existingVPCInfo *common.VPCResourceInfo + subnetCRTags []model.Tag + expectAllSubnetNum int + expectAllSubnetNumAfterCreate int + expectCreateSubnetUID string + }{ + { + name: "Subnet does not exist", + existingSubnetCR: subnet, + expectAllSubnetNum: 0, + existingVPCInfo: vpcResourceInfo, + prepareFunc: func() *gomonkey.Patches { + var fakeVpcSubnet = model.VpcSubnet{Path: &fakeSubnetPath, Id: &nsxSubnetID, Tags: basicTags} + patches := gomonkey.ApplyMethod(reflect.TypeOf(&fakeSubnetsClient{}), "Get", func(_ *fakeSubnetsClient, orgIdParam string, projectIdParam string, vpcIdParam string, subnetIdParam string) (model.VpcSubnet, error) { + return fakeVpcSubnet, nil + }) + return patches + }, + subnetCRTags: []model.Tag{}, + expectAllSubnetNumAfterCreate: 1, + expectCreateSubnetUID: fakeSubnetPath, + }, + { + name: "Subnet exists and not change", + existingSubnetCR: subnet, + existingVPCInfo: vpcResourceInfo, + prepareFunc: func() *gomonkey.Patches { + patches := gomonkey.ApplyMethod(reflect.TypeOf(&fakeQueryClient{}), "List", func(_ *fakeQueryClient, _ string, _ *string, _ *string, _ *int64, _ *bool, _ *string) (model.SearchResponse, error) { + cursor := "1" + resultCount := int64(1) + tags := data.NewListValue() + for _, basicTag := range basicTags { + tags.Add(data.NewStructValue("", map[string]data.DataValue{"scope": data.NewStringValue(*basicTag.Scope), "tag": data.NewStringValue(*basicTag.Tag)})) + } + mode := "DHCP_DEACTIVATED" + dhcpConfig := data.NewStructValue("", map[string]data.DataValue{"mode": data.NewStringValue(mode)}) + return model.SearchResponse{ + Results: []*data.StructValue{data.NewStructValue("", + map[string]data.DataValue{ + "resource_type": data.NewStringValue("VpcSubnet"), + "id": data.NewStringValue(nsxSubnetID), + "display_name": data.NewStringValue(subnetName), + "path": data.NewStringValue(fakeSubnetPath), + "tags": tags, + "subnet_dhcp_config": dhcpConfig, + })}, + Cursor: &cursor, ResultCount: &resultCount, + }, nil + }) + return patches + }, + expectAllSubnetNum: 1, + expectAllSubnetNumAfterCreate: 1, + expectCreateSubnetUID: subnetID, + }, + { + name: "Subnet exists and changed", + existingSubnetCR: subnet, + existingVPCInfo: vpcResourceInfo, + prepareFunc: func() *gomonkey.Patches { + patches := gomonkey.ApplyMethod(reflect.TypeOf(&fakeQueryClient{}), "List", func(_ *fakeQueryClient, _ string, _ *string, _ *string, _ *int64, _ *bool, _ *string) (model.SearchResponse, error) { + cursor := "1" + resultCount := int64(1) + tags := data.NewListValue() + for _, basicTag := range basicTags { + tags.Add(data.NewStructValue("", map[string]data.DataValue{"scope": data.NewStringValue(*basicTag.Scope), "tag": data.NewStringValue(*basicTag.Tag)})) + } + tags.Add(data.NewStructValue("", map[string]data.DataValue{"scope": data.NewStringValue("fakeScope"), "tag": data.NewStringValue("fakeTag")})) + return model.SearchResponse{ + Results: []*data.StructValue{data.NewStructValue("", + map[string]data.DataValue{ + "resource_type": data.NewStringValue("VpcSubnet"), + "id": data.NewStringValue(nsxSubnetID), + "display_name": data.NewStringValue(subnetName), + "path": data.NewStringValue(fakeSubnetPath), + "tags": tags, + })}, + Cursor: &cursor, ResultCount: &resultCount, + }, nil + }) + var fakeVpcSubnet = model.VpcSubnet{Path: &fakeSubnetPath, Id: &nsxSubnetID, Tags: basicTags} + patches.ApplyMethod(reflect.TypeOf(&fakeSubnetsClient{}), "Get", func(_ *fakeSubnetsClient, orgIdParam string, projectIdParam string, vpcIdParam string, subnetIdParam string) (model.VpcSubnet, error) { + return fakeVpcSubnet, nil + }) + return patches + }, + expectAllSubnetNum: 1, + expectAllSubnetNumAfterCreate: 1, + expectCreateSubnetUID: fakeSubnetPath, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + newScheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(newScheme)) + utilruntime.Must(v1alpha1.AddToScheme(newScheme)) + fakeClient := fake.NewClientBuilder().WithScheme(newScheme).Build() + commonService := common.Service{ + Client: fakeClient, + NSXClient: &nsx.Client{ + OrgRootClient: &fakeOrgRootClient{}, + SubnetsClient: &fakeSubnetsClient{}, + QueryClient: &fakeQueryClient{}, + RealizedEntitiesClient: &fakeRealizedEntitiesClient{}, + NsxConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: clusterName, + }, + }, + }, + NSXConfig: &config.NSXOperatorConfig{ + CoeConfig: &config.CoeConfig{ + Cluster: clusterName, + }, + }, + } + if tc.prepareFunc != nil { + patches := tc.prepareFunc() + defer patches.Reset() + } + + service, err := InitializeSubnetService(commonService) + + assert.NoError(t, err) + res := service.ListAllSubnet() + assert.Equal(t, tc.expectAllSubnetNum, len(res)) - err = service.DeleteSubnet(fakeVpcSubnet) - assert.NoError(t, err) + createdNSXSubnetUID, err := service.CreateOrUpdateSubnet(tc.existingSubnetCR, *tc.existingVPCInfo, tc.subnetCRTags) + assert.NoError(t, err) + assert.Equal(t, tc.expectCreateSubnetUID, createdNSXSubnetUID) - err = service.Cleanup(context.TODO()) - assert.NoError(t, err) + res = service.ListAllSubnet() + + assert.Equal(t, tc.expectAllSubnetNumAfterCreate, len(res)) + + nsxSubnets := service.GetSubnetsByIndex(common.TagScopeSubnetCRUID, subnetID) + assert.Equal(t, 1, len(nsxSubnets)) + + getByKey, err := service.GetSubnetByKey(nsxSubnetID) + assert.NoError(t, err) + assert.Equal(t, fakeSubnetPath, *getByKey.Path) + + getByPath, err := service.GetSubnetByPath(fakeSubnetPath) + assert.NoError(t, err) + assert.Equal(t, nsxSubnetID, *getByPath.Id) + + err = service.Cleanup(context.TODO()) + assert.NoError(t, err) + + assert.Equal(t, 0, len(service.ListAllSubnet())) + }) + } } func TestSubnetService_UpdateSubnetSet(t *testing.T) { + fakeSubnetPath := "/orgs/default/projects/nsx_operator_e2e_test/vpcs/subnet-e2e_xxxx/subnets/subnet_id" mockCtl := gomock.NewController(t) k8sClient := mock_client.NewMockClient(mockCtl) defer mockCtl.Finish()