From 67b24a40c7b04f6a208ace178c87759efd913fba Mon Sep 17 00:00:00 2001 From: Stoyan Rachev Date: Wed, 25 Aug 2021 15:26:06 +0300 Subject: [PATCH] Add unit tests for infrastructure ConfigValidator --- .../infrastructure/configvalidator_test.go | 156 ++++++++++++++++++ .../infrastructure_suite_test.go | 27 +++ pkg/gcp/client/mock/doc.go | 2 +- pkg/gcp/client/mock/mocks.go | 40 ++++- 4 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 pkg/controller/infrastructure/configvalidator_test.go create mode 100644 pkg/controller/infrastructure/infrastructure_suite_test.go diff --git a/pkg/controller/infrastructure/configvalidator_test.go b/pkg/controller/infrastructure/configvalidator_test.go new file mode 100644 index 000000000..587abcf9a --- /dev/null +++ b/pkg/controller/infrastructure/configvalidator_test.go @@ -0,0 +1,156 @@ +// Copyright (c) 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infrastructure_test + +import ( + "context" + "encoding/json" + "errors" + + apisgcp "github.com/gardener/gardener-extension-provider-gcp/pkg/apis/gcp" + . "github.com/gardener/gardener-extension-provider-gcp/pkg/controller/infrastructure" + "github.com/gardener/gardener-extension-provider-gcp/pkg/gcp" + mockgcpclient "github.com/gardener/gardener-extension-provider-gcp/pkg/gcp/client/mock" + + "github.com/gardener/gardener/extensions/pkg/controller/infrastructure" + extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" + mockclient "github.com/gardener/gardener/pkg/mock/controller-runtime/client" + . "github.com/gardener/gardener/pkg/utils/test/matchers" + "github.com/go-logr/logr" + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gstruct" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/runtime/inject" +) + +const ( + name = "infrastructure" + namespace = "shoot--foobar--gcp" + region = "europe-west1" +) + +var _ = Describe("ConfigValidator", func() { + var ( + ctrl *gomock.Controller + c *mockclient.MockClient + gcpClientFactory *mockgcpclient.MockFactory + gcpComputeClient *mockgcpclient.MockComputeClient + ctx context.Context + logger logr.Logger + cv infrastructure.ConfigValidator + infra *extensionsv1alpha1.Infrastructure + ) + + BeforeEach(func() { + ctrl = gomock.NewController(GinkgoT()) + + c = mockclient.NewMockClient(ctrl) + gcpClientFactory = mockgcpclient.NewMockFactory(ctrl) + gcpComputeClient = mockgcpclient.NewMockComputeClient(ctrl) + + ctx = context.TODO() + logger = log.Log.WithName("test") + + cv = NewConfigValidator(gcpClientFactory, logger) + err := cv.(inject.Client).InjectClient(c) + Expect(err).NotTo(HaveOccurred()) + + infra = &extensionsv1alpha1.Infrastructure{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: extensionsv1alpha1.InfrastructureSpec{ + DefaultSpec: extensionsv1alpha1.DefaultSpec{ + Type: gcp.Type, + ProviderConfig: &runtime.RawExtension{ + Raw: encode(&apisgcp.InfrastructureConfig{ + Networks: apisgcp.NetworkConfig{ + CloudNAT: &apisgcp.CloudNAT{ + NatIPNames: []apisgcp.NatIPName{ + {Name: "test1"}, + {Name: "test2"}, + }, + }, + }, + }), + }, + }, + Region: region, + SecretRef: corev1.SecretReference{ + Name: name, + Namespace: namespace, + }, + }, + } + }) + + AfterEach(func() { + ctrl.Finish() + }) + + Describe("#Validate", func() { + It("should forbid NAT IP names that don't exist or are not available", func() { + gcpClientFactory.EXPECT().NewComputeClient(ctx, c, infra.Spec.SecretRef).Return(gcpComputeClient, nil) + gcpComputeClient.EXPECT().GetExternalAddresses(ctx, region).Return(map[string]bool{ + "test2": false, + }, nil) + + errorList := cv.Validate(ctx, infra) + Expect(errorList).To(ConsistOfFields(Fields{ + "Type": Equal(field.ErrorTypeNotFound), + "Field": Equal("networks.cloudNAT.natIPNames[0].name"), + }, Fields{ + "Type": Equal(field.ErrorTypeInvalid), + "Field": Equal("networks.cloudNAT.natIPNames[1].name"), + "Detail": Equal("external IP address is already in use"), + })) + }) + + It("should allow NAT IP names that exist and are available", func() { + gcpClientFactory.EXPECT().NewComputeClient(ctx, c, infra.Spec.SecretRef).Return(gcpComputeClient, nil) + gcpComputeClient.EXPECT().GetExternalAddresses(ctx, region).Return(map[string]bool{ + "test1": true, + "test2": true, + }, nil) + + errorList := cv.Validate(ctx, infra) + Expect(errorList).To(BeEmpty()) + }) + + It("should fail with InternalError if getting external addresses failed", func() { + gcpClientFactory.EXPECT().NewComputeClient(ctx, c, infra.Spec.SecretRef).Return(gcpComputeClient, nil) + gcpComputeClient.EXPECT().GetExternalAddresses(ctx, region).Return(nil, errors.New("test")) + + errorList := cv.Validate(ctx, infra) + Expect(errorList).To(ConsistOfFields(Fields{ + "Type": Equal(field.ErrorTypeInternal), + "Field": Equal("networks.cloudNAT"), + "Detail": Equal("could not get external IP addresses: test"), + })) + }) + }) +}) + +func encode(obj runtime.Object) []byte { + data, _ := json.Marshal(obj) + return data +} diff --git a/pkg/controller/infrastructure/infrastructure_suite_test.go b/pkg/controller/infrastructure/infrastructure_suite_test.go new file mode 100644 index 000000000..a23267e4b --- /dev/null +++ b/pkg/controller/infrastructure/infrastructure_suite_test.go @@ -0,0 +1,27 @@ +// Copyright (c) 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infrastructure_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestInfrastructure(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Infrastructure Suite") +} diff --git a/pkg/gcp/client/mock/doc.go b/pkg/gcp/client/mock/doc.go index 97e9fc81e..d8423df95 100644 --- a/pkg/gcp/client/mock/doc.go +++ b/pkg/gcp/client/mock/doc.go @@ -12,6 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:generate mockgen -package client -destination=mocks.go github.com/gardener/gardener-extension-provider-gcp/pkg/gcp/client Factory,DNSClient +//go:generate mockgen -package client -destination=mocks.go github.com/gardener/gardener-extension-provider-gcp/pkg/gcp/client Factory,DNSClient,ComputeClient package client diff --git a/pkg/gcp/client/mock/mocks.go b/pkg/gcp/client/mock/mocks.go index e9946814a..3aedf3884 100644 --- a/pkg/gcp/client/mock/mocks.go +++ b/pkg/gcp/client/mock/mocks.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/gardener/gardener-extension-provider-gcp/pkg/gcp/client (interfaces: Factory,DNSClient) +// Source: github.com/gardener/gardener-extension-provider-gcp/pkg/gcp/client (interfaces: Factory,DNSClient,ComputeClient) // Package client is a generated GoMock package. package client @@ -147,3 +147,41 @@ func (mr *MockDNSClientMockRecorder) GetManagedZones(arg0 interface{}) *gomock.C mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManagedZones", reflect.TypeOf((*MockDNSClient)(nil).GetManagedZones), arg0) } + +// MockComputeClient is a mock of ComputeClient interface. +type MockComputeClient struct { + ctrl *gomock.Controller + recorder *MockComputeClientMockRecorder +} + +// MockComputeClientMockRecorder is the mock recorder for MockComputeClient. +type MockComputeClientMockRecorder struct { + mock *MockComputeClient +} + +// NewMockComputeClient creates a new mock instance. +func NewMockComputeClient(ctrl *gomock.Controller) *MockComputeClient { + mock := &MockComputeClient{ctrl: ctrl} + mock.recorder = &MockComputeClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockComputeClient) EXPECT() *MockComputeClientMockRecorder { + return m.recorder +} + +// GetExternalAddresses mocks base method. +func (m *MockComputeClient) GetExternalAddresses(arg0 context.Context, arg1 string) (map[string]bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetExternalAddresses", arg0, arg1) + ret0, _ := ret[0].(map[string]bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetExternalAddresses indicates an expected call of GetExternalAddresses. +func (mr *MockComputeClientMockRecorder) GetExternalAddresses(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExternalAddresses", reflect.TypeOf((*MockComputeClient)(nil).GetExternalAddresses), arg0, arg1) +}