Skip to content

Commit

Permalink
Example mocked envtest
Browse files Browse the repository at this point in the history
  • Loading branch information
mdbooth committed May 6, 2022
1 parent 76154bd commit 391f09f
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 44 deletions.
78 changes: 35 additions & 43 deletions controllers/openstackcluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import (
"context"
"fmt"

"github.com/golang/mock/gomock"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -32,6 +35,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"

infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5"
"sigs.k8s.io/cluster-api-provider-openstack/pkg/clients"
mock_clients "sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mocks"
"sigs.k8s.io/cluster-api-provider-openstack/pkg/scope"
)

var (
Expand Down Expand Up @@ -167,49 +173,35 @@ var _ = Describe("OpenStackCluster controller", func() {
})

// TODO: This test is set to pending (PIt instead of It) since it is not working.
PIt("should be able to reconcile when basition disabled", func() {
// verify := false
// cloud := clientconfig.Cloud{
// Cloud: "test",
// RegionName: "test",
// Verify: &verify,
// AuthInfo: &clientconfig.AuthInfo{
// AuthURL: "https://example.com:5000",
// Username: "testuser",
// Password: "secret",
// ProjectName: "test",
// DomainName: "test",
// UserDomainName: "test",
// },
// }
// // TODO: Can we fake the client in some way?
// providerClient, clientOpts, _, err := provider.NewClient(cloud, nil)
// Expect(err).To(BeNil())
// scope := &scope.Scope{
// ProviderClient: providerClient,
// ProviderClientOpts: clientOpts,
// }

// TODO: This won't work without filling in proper values.
/*
scope := &scope.Scope{
ProviderClient: &gophercloud.ProviderClient{},
ProviderClientOpts: &clientconfig.ClientOpts{},
}
testCluster.SetName("no-bastion")
testCluster.Spec = infrav1.OpenStackClusterSpec{
Bastion: &infrav1.Bastion{
Enabled: false,
},
}
err := k8sClient.Create(ctx, testCluster)
Expect(err).To(BeNil())
err = k8sClient.Create(ctx, capiCluster)
Expect(err).To(BeNil())
err = deleteBastion(scope, capiCluster, testCluster)
Expect(err).To(BeNil())
*/
It("should be able to reconcile when basition disabled", func() {
mockCtrl := gomock.NewController(GinkgoT())
computeClient := mock_clients.NewMockComputeClient(mockCtrl)
networkClient := mock_clients.NewMockNetworkClient(mockCtrl)
loadBalancerClient := mock_clients.NewMockLoadBalancerClient(mockCtrl)

scope := scope.NewMockScopeFactory(computeClient, networkClient, loadBalancerClient)

computeClientRecorder := computeClient.EXPECT()
computeClientRecorder.ListServers(servers.ListOpts{
Name: "^capi-cluster-bastion$",
}).Return([]clients.ServerExt{}, nil)

networkClientRecorder := networkClient.EXPECT()
networkClientRecorder.ListSecGroup(gomock.Any()).Return([]groups.SecGroup{}, nil)

testCluster.SetName("no-bastion")
testCluster.Spec = infrav1.OpenStackClusterSpec{
Bastion: &infrav1.Bastion{
Enabled: false,
},
}
err := k8sClient.Create(ctx, testCluster)
Expect(err).To(BeNil())
err = k8sClient.Create(ctx, capiCluster)
Expect(err).To(BeNil())

err = deleteBastion(scope, capiCluster, testCluster)
Expect(err).To(BeNil())
})
})

Expand Down
69 changes: 69 additions & 0 deletions pkg/scope/mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
Copyright 2022 The Kubernetes Authors.
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 scope

import (
"context"

"github.com/go-logr/logr"
"sigs.k8s.io/controller-runtime/pkg/client"

infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5"
"sigs.k8s.io/cluster-api-provider-openstack/pkg/clients"
mock_clients "sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mocks"
)

// MockScopeFactory implements both the ScopeFactory and ClientScope interfaces. It can be used in place of the default ProviderScopeFactory
// when we want to use mocked service clients which do not attempt to connect to a running OpenStack cloud.
type MockScopeFactory struct {
ComputeClient *mock_clients.MockComputeClient
NetworkClient *mock_clients.MockNetworkClient
LoadBalancerClient *mock_clients.MockLoadBalancerClient
baseScope
}

func NewMockScopeFactory(computeClient *mock_clients.MockComputeClient, networkClient *mock_clients.MockNetworkClient, loadBalancerClient *mock_clients.MockLoadBalancerClient) *MockScopeFactory {
return &MockScopeFactory{
ComputeClient: computeClient,
NetworkClient: networkClient,
LoadBalancerClient: loadBalancerClient,
baseScope: baseScope{
projectID: "",
logger: logr.Discard(),
},
}
}

func (f *MockScopeFactory) NewClientScopeFromMachine(ctx context.Context, ctrlClient client.Client, openStackMachine *infrav1.OpenStackMachine, logger logr.Logger) (ClientScope, error) {
return f, nil
}

func (f *MockScopeFactory) NewClientScopeFromCluster(ctx context.Context, ctrlClient client.Client, openStackCluster *infrav1.OpenStackCluster, logger logr.Logger) (ClientScope, error) {
return f, nil
}

func (f *MockScopeFactory) NewComputeClient() (clients.ComputeClient, error) {
return f.ComputeClient, nil
}

func (f *MockScopeFactory) NewNetworkClient() (clients.NetworkClient, error) {
return f.NetworkClient, nil
}

func (f *MockScopeFactory) NewLoadBalancerClient() (clients.LoadBalancerClient, error) {
return f.LoadBalancerClient, nil
}
1 change: 1 addition & 0 deletions pkg/scope/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
caSecretKey = "cacert"
)

// ProviderScopeFactory is the default scope factory. It generates service clients which make OpenStack API calls against a running cloud.
var ProviderScopeFactory Factory = providerScopeFactory{}

type providerScopeFactory struct{}
Expand Down
4 changes: 3 additions & 1 deletion pkg/scope/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,21 @@ import (
"sigs.k8s.io/cluster-api-provider-openstack/pkg/clients"
)

// Factory instantiates a new ClientScope using credentials from either a cluster or a machine.
type Factory interface {
NewClientScopeFromMachine(ctx context.Context, ctrlClient client.Client, openStackMachine *infrav1.OpenStackMachine, logger logr.Logger) (ClientScope, error)
NewClientScopeFromCluster(ctx context.Context, ctrlClient client.Client, openStackCluster *infrav1.OpenStackCluster, logger logr.Logger) (ClientScope, error)
}

// ClientScope is a Scope that can also be used to create service clients.
type ClientScope interface {
NewComputeClient() (clients.ComputeClient, error)
NewNetworkClient() (clients.NetworkClient, error)
NewLoadBalancerClient() (clients.LoadBalancerClient, error)
Scope
}

// Scope is used to initialize Services from Controllers.
// Scope contains arguments common to most operations.
type Scope interface {
Logger() logr.Logger
ProjectID() string
Expand Down

0 comments on commit 391f09f

Please sign in to comment.