Skip to content

Commit 8401518

Browse files
authored
Add unit tests for PowerVS (#579)
1 parent b1756ed commit 8401518

File tree

2 files changed

+393
-0
lines changed

2 files changed

+393
-0
lines changed

cloud/scope/powervs_test.go

Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package scope
18+
19+
import (
20+
"encoding/base64"
21+
"errors"
22+
23+
"github.com/golang/mock/gomock"
24+
. "github.com/onsi/ginkgo"
25+
. "github.com/onsi/gomega"
26+
27+
"github.com/IBM-Cloud/power-go-client/power/models"
28+
corev1 "k8s.io/api/core/v1"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/client-go/kubernetes/scheme"
31+
"k8s.io/klog/v2/klogr"
32+
"k8s.io/utils/pointer"
33+
infrav1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta1"
34+
"sigs.k8s.io/cluster-api-provider-ibmcloud/pkg/cloud/services/powervs/mock"
35+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
36+
"sigs.k8s.io/controller-runtime/pkg/client"
37+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
38+
)
39+
40+
var (
41+
mockpowervs *mock.MockPowerVS
42+
)
43+
44+
func newMachine(clusterName, machineName string) *clusterv1.Machine {
45+
return &clusterv1.Machine{
46+
ObjectMeta: metav1.ObjectMeta{
47+
Name: machineName,
48+
Namespace: "default",
49+
},
50+
Spec: clusterv1.MachineSpec{
51+
Bootstrap: clusterv1.Bootstrap{
52+
DataSecretName: pstring(machineName),
53+
},
54+
},
55+
}
56+
}
57+
58+
func newCluster(name string) *clusterv1.Cluster {
59+
return &clusterv1.Cluster{
60+
ObjectMeta: metav1.ObjectMeta{
61+
Name: name,
62+
Namespace: "default",
63+
},
64+
Spec: clusterv1.ClusterSpec{},
65+
}
66+
}
67+
68+
func newBootstrapSecret(clusterName, machineName string) *corev1.Secret {
69+
return &corev1.Secret{
70+
ObjectMeta: metav1.ObjectMeta{
71+
Labels: map[string]string{
72+
clusterv1.ClusterLabelName: clusterName,
73+
},
74+
Name: machineName,
75+
Namespace: "default",
76+
},
77+
Data: map[string][]byte{
78+
"value": []byte("user data"),
79+
},
80+
}
81+
}
82+
83+
func newPowerVSCluster(name string) *infrav1.IBMPowerVSCluster {
84+
return &infrav1.IBMPowerVSCluster{
85+
ObjectMeta: metav1.ObjectMeta{
86+
Name: name,
87+
Namespace: "default",
88+
},
89+
}
90+
}
91+
92+
func newPowerVSMachine(clusterName, machineName string, imageRef *string, networkRef *string, isID bool) *infrav1.IBMPowerVSMachine {
93+
image := &infrav1.IBMPowerVSResourceReference{}
94+
network := infrav1.IBMPowerVSResourceReference{}
95+
96+
if !isID {
97+
image.Name = imageRef
98+
network.Name = networkRef
99+
} else {
100+
image.ID = imageRef
101+
network.ID = networkRef
102+
}
103+
104+
return &infrav1.IBMPowerVSMachine{
105+
ObjectMeta: metav1.ObjectMeta{
106+
Labels: map[string]string{
107+
clusterv1.ClusterLabelName: clusterName,
108+
},
109+
Name: machineName,
110+
Namespace: "default",
111+
},
112+
Spec: infrav1.IBMPowerVSMachineSpec{
113+
Memory: "8",
114+
Processors: "0.25",
115+
Image: image,
116+
Network: network,
117+
},
118+
}
119+
}
120+
121+
func pstring(name string) *string {
122+
return pointer.String(name)
123+
}
124+
125+
func setupPowerVSMachineScope(clusterName string, machineName string, imageID *string, networkID *string, isID bool) (*PowerVSMachineScope, error) {
126+
cluster := newCluster(clusterName)
127+
machine := newMachine(clusterName, machineName)
128+
secret := newBootstrapSecret(clusterName, machineName)
129+
powervsMachine := newPowerVSMachine(clusterName, machineName, imageID, networkID, isID)
130+
powervsCluster := newPowerVSCluster(clusterName)
131+
132+
initObjects := []client.Object{
133+
cluster, machine, secret, powervsCluster, powervsMachine,
134+
}
135+
136+
client := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(initObjects...).Build()
137+
return &PowerVSMachineScope{
138+
client: client,
139+
Logger: klogr.New(),
140+
IBMPowerVSClient: mockpowervs,
141+
Cluster: cluster,
142+
Machine: machine,
143+
IBMPowerVSCluster: powervsCluster,
144+
IBMPowerVSMachine: powervsMachine,
145+
}, nil
146+
}
147+
148+
var _ = Describe("PowerVS machine and image creation", func() {
149+
var (
150+
ctrl *gomock.Controller
151+
)
152+
153+
BeforeEach(func() {
154+
ctrl = gomock.NewController(GinkgoT())
155+
mockpowervs = mock.NewMockPowerVS(ctrl)
156+
157+
})
158+
159+
AfterEach(func() {
160+
ctrl.Finish()
161+
})
162+
163+
Context("Create an IBMPowerVSMachine", func() {
164+
var instances *models.PVMInstances
165+
166+
BeforeEach(func() {
167+
instances = &models.PVMInstances{}
168+
})
169+
170+
It("should not error and create a machine", func() {
171+
172+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-ID"), pstring("test-net-ID"), true)
173+
Expect(err).NotTo(HaveOccurred())
174+
175+
instanceList := &models.PVMInstanceList{
176+
{
177+
PvmInstanceID: pstring("abcd-test-machine"),
178+
},
179+
}
180+
body := &models.PVMInstanceCreate{
181+
ServerName: &scope.IBMPowerVSMachine.Name,
182+
Memory: pointer.Float64(8),
183+
Processors: pointer.Float64(0.25),
184+
ImageID: pstring("test-image-ID"),
185+
KeyPairName: "dummy-key",
186+
}
187+
188+
mockpowervs.EXPECT().GetAllInstance().Return(instances, nil)
189+
mockpowervs.EXPECT().CreateInstance(gomock.AssignableToTypeOf(body)).Return(instanceList, nil)
190+
191+
_, err = scope.CreateMachine()
192+
Expect(err).NotTo(HaveOccurred())
193+
})
194+
195+
It("should error with instance not getting created as bootstrap data is not available", func() {
196+
scope, err := setupPowerVSMachineScope("test-cluster", "", pstring("test-image-ID"), pstring("test-net-ID"), true)
197+
Expect(err).NotTo(HaveOccurred())
198+
199+
scope.Machine.Spec.Bootstrap.DataSecretName = nil
200+
mockpowervs.EXPECT().GetAllInstance().Return(instances, nil)
201+
202+
_, err = scope.CreateMachine()
203+
Expect(err).To(HaveOccurred())
204+
})
205+
})
206+
207+
Context("Delete IBMPowerVS machine", func() {
208+
var instance *models.PVMInstance
209+
210+
BeforeEach(func() {
211+
instance = &models.PVMInstance{
212+
PvmInstanceID: pstring("abcd-test-machine"),
213+
}
214+
})
215+
216+
It("should not error and delete the machine", func() {
217+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-ID"), pstring("test-net-ID"), true)
218+
Expect(err).NotTo(HaveOccurred())
219+
220+
mockpowervs.EXPECT().DeleteInstance(gomock.AssignableToTypeOf(*instance.PvmInstanceID)).Return(nil)
221+
err = scope.DeleteMachine()
222+
Expect(err).NotTo(HaveOccurred())
223+
})
224+
225+
It("should error with machine not being deleted", func() {
226+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-ID"), pstring("test-net-ID"), true)
227+
Expect(err).NotTo(HaveOccurred())
228+
229+
mockpowervs.EXPECT().DeleteInstance(gomock.AssignableToTypeOf(*instance.PvmInstanceID)).Return(errors.New("Could not delete the macine"))
230+
err = scope.DeleteMachine()
231+
Expect(err).To(HaveOccurred())
232+
233+
})
234+
})
235+
236+
Context("Get image ID or network ID", func() {
237+
It("should not error and get imageID from name", func() {
238+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-name"), pstring("test-net-name"), false)
239+
Expect(err).NotTo(HaveOccurred())
240+
241+
images := &models.Images{
242+
Images: []*models.ImageReference{
243+
{
244+
ImageID: pstring("test-image-ID"),
245+
Name: pstring("test-image-name"),
246+
},
247+
},
248+
}
249+
mockpowervs.EXPECT().GetAllImage().Return(images, nil)
250+
251+
mspec := scope.IBMPowerVSMachine.Spec
252+
_, err = getImageID(mspec.Image, scope)
253+
Expect(err).NotTo(HaveOccurred())
254+
})
255+
256+
It("should error and not find the corresponding imageID", func() {
257+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-name"), pstring("test-net-name"), false)
258+
Expect(err).NotTo(HaveOccurred())
259+
260+
images := &models.Images{
261+
Images: []*models.ImageReference{
262+
{
263+
ImageID: pstring("test-diff-image-ID"),
264+
Name: pstring("test-diff-image-name"),
265+
},
266+
},
267+
}
268+
mockpowervs.EXPECT().GetAllImage().Return(images, nil)
269+
270+
mspec := scope.IBMPowerVSMachine.Spec
271+
_, err = getImageID(mspec.Image, scope)
272+
Expect(err).To(HaveOccurred())
273+
})
274+
275+
It("should not error and get networkID from name", func() {
276+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-name"), pstring("test-net-name"), false)
277+
Expect(err).NotTo(HaveOccurred())
278+
279+
networks := &models.Networks{
280+
Networks: []*models.NetworkReference{
281+
{
282+
NetworkID: pstring("test-net-ID"),
283+
Name: pstring("test-net-name"),
284+
},
285+
},
286+
}
287+
mockpowervs.EXPECT().GetAllNetwork().Return(networks, nil)
288+
289+
mspec := scope.IBMPowerVSMachine.Spec
290+
_, err = getNetworkID(mspec.Network, scope)
291+
Expect(err).NotTo(HaveOccurred())
292+
})
293+
294+
It("should error and not find the corresponding networkID", func() {
295+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-name"), pstring("test-net-name"), false)
296+
Expect(err).NotTo(HaveOccurred())
297+
298+
networks := &models.Networks{
299+
Networks: []*models.NetworkReference{
300+
{
301+
NetworkID: pstring("test-diff-net-ID"),
302+
Name: pstring("test-diff-net-name"),
303+
},
304+
},
305+
}
306+
mockpowervs.EXPECT().GetAllNetwork().Return(networks, nil)
307+
308+
mspec := scope.IBMPowerVSMachine.Spec
309+
_, err = getNetworkID(mspec.Network, scope)
310+
Expect(err).To(HaveOccurred())
311+
})
312+
})
313+
314+
Context("Get Bootstrap Data", func() {
315+
It("should not error and get base64 encoded bootstrap data", func() {
316+
317+
scope, err := setupPowerVSMachineScope("test-cluster", "test-machine-0", pstring("test-image-ID"), pstring("test-net-ID"), true)
318+
Expect(err).NotTo(HaveOccurred())
319+
320+
result, err := scope.GetBootstrapData()
321+
Expect(err).NotTo(HaveOccurred())
322+
Expect(result).NotTo(BeNil())
323+
324+
_, err = base64.StdEncoding.DecodeString(result)
325+
Expect(err).NotTo(HaveOccurred())
326+
})
327+
})
328+
})

cloud/scope/suite_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package scope
17+
18+
import (
19+
"path/filepath"
20+
"testing"
21+
22+
. "github.com/onsi/ginkgo"
23+
"github.com/onsi/ginkgo/reporters"
24+
. "github.com/onsi/gomega"
25+
"k8s.io/client-go/kubernetes/scheme"
26+
"k8s.io/client-go/rest"
27+
infrav1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta1"
28+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
29+
"sigs.k8s.io/controller-runtime/pkg/envtest"
30+
)
31+
32+
var cfg *rest.Config
33+
var testEnv *envtest.Environment
34+
35+
func TestScope(t *testing.T) {
36+
RegisterFailHandler(Fail)
37+
junitReporter := reporters.NewJUnitReporter("junit-scope.xml")
38+
RunSpecsWithDefaultAndCustomReporters(t, "Cloud Suite", []Reporter{junitReporter})
39+
40+
}
41+
42+
var _ = BeforeSuite(func(done Done) {
43+
By("bootstrapping test environment")
44+
testEnv = &envtest.Environment{
45+
CRDDirectoryPaths: []string{
46+
filepath.Join("..", "config", "crd", "bases"),
47+
},
48+
}
49+
50+
var err error
51+
cfg, err = testEnv.Start()
52+
Expect(err).ToNot(HaveOccurred())
53+
Expect(cfg).ToNot(BeNil())
54+
55+
Expect(clusterv1.AddToScheme(scheme.Scheme)).To(Succeed())
56+
Expect(infrav1.AddToScheme(scheme.Scheme)).To(Succeed())
57+
58+
close(done)
59+
}, 60)
60+
61+
var _ = AfterSuite(func() {
62+
By("tearing down the test environment")
63+
err := testEnv.Stop()
64+
Expect(err).ToNot(HaveOccurred())
65+
})

0 commit comments

Comments
 (0)