Skip to content

Commit

Permalink
Add unit tests for client code
Browse files Browse the repository at this point in the history
Co-authored-by: Alexander Wels <awels@redhat.com>
Signed-off-by: Michael Henriksen <mhenriks@redhat.com>
  • Loading branch information
mhenriks and awels committed Mar 20, 2024
1 parent ccd8fa5 commit 001fd0b
Show file tree
Hide file tree
Showing 20 changed files with 1,609 additions and 7 deletions.
17 changes: 12 additions & 5 deletions pkg/kubevirt/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
kubevirtv1 "kubevirt.io/api/core/v1"
cdicli "kubevirt.io/client-go/generated/containerized-data-importer/clientset/versioned"
"kubevirt.io/client-go/kubecli"
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
)
Expand All @@ -37,8 +38,9 @@ type Client interface {
}

type client struct {
kubernetesClient *kubernetes.Clientset
kubernetesClient kubernetes.Interface
virtClient kubecli.KubevirtClient
cdiClient cdicli.Interface
infraLabelMap map[string]string
volumePrefix string
}
Expand All @@ -57,7 +59,12 @@ func NewClient(config *rest.Config, infraClusterLabelMap map[string]string, pref
if err != nil {
return nil, err
}
cdiClient, err := cdicli.NewForConfig(config)
if err != nil {
return nil, err
}
result.virtClient = kubevirtClient
result.cdiClient = cdiClient
result.infraLabelMap = infraClusterLabelMap
result.volumePrefix = fmt.Sprintf("%s-", prefix)
return result, nil
Expand Down Expand Up @@ -135,13 +142,13 @@ func (c *client) CreateDataVolume(namespace string, dataVolume *cdiv1.DataVolume
if !strings.HasPrefix(dataVolume.GetName(), c.volumePrefix) {
return nil, ErrInvalidVolume
} else {
return c.virtClient.CdiClient().CdiV1beta1().DataVolumes(namespace).Create(context.TODO(), dataVolume, metav1.CreateOptions{})
return c.cdiClient.CdiV1beta1().DataVolumes(namespace).Create(context.TODO(), dataVolume, metav1.CreateOptions{})
}
}

// Ping performs a minimal request to the infra-cluster k8s api
func (c *client) Ping(ctx context.Context) error {
_, err := c.kubernetesClient.ServerVersion()
_, err := c.kubernetesClient.Discovery().ServerVersion()
return err
}

Expand All @@ -152,13 +159,13 @@ func (c *client) DeleteDataVolume(namespace string, name string) error {
} else if err != nil {
return err
} else if dv != nil {
return c.virtClient.CdiClient().CdiV1beta1().DataVolumes(namespace).Delete(context.TODO(), dv.Name, metav1.DeleteOptions{})
return c.cdiClient.CdiV1beta1().DataVolumes(namespace).Delete(context.TODO(), dv.Name, metav1.DeleteOptions{})
}
return nil
}

func (c *client) GetDataVolume(namespace string, name string) (*cdiv1.DataVolume, error) {
dv, err := c.virtClient.CdiClient().CdiV1beta1().DataVolumes(namespace).Get(context.TODO(), name, metav1.GetOptions{})
dv, err := c.cdiClient.CdiV1beta1().DataVolumes(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, err
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/kubevirt/client_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package kubevirt

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestClient(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "kubevirt client Suite")
}
170 changes: 170 additions & 0 deletions pkg/kubevirt/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package kubevirt

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

k8sv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
k8sfake "k8s.io/client-go/kubernetes/fake"
"k8s.io/utils/pointer"
fakecdi "kubevirt.io/client-go/generated/containerized-data-importer/clientset/versioned/fake"
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
)

const (
storageClassName = "test-storage-class"
testVolumeName = "test-volume"
testVolumeNameNotAllowed = "test-volume-not-allowed"
validDataVolume = "pvc-valid-data-volume"
nolabelDataVolume = "nolabel-data-volume"
testClaimName = "pvc-valid-data-volume"
testClaimName2 = "pvc-valid-data-volume2"
testClaimName3 = "pvc-valid-data-volume3"
testNamespace = "test-namespace"
unboundTestClaimName = "unbound-test-claim"
)

var _ = Describe("Client", func() {
var (
c *client
)

Context("volumes", func() {
BeforeEach(func() {
// Setup code before each test
c = NewFakeClient()
c = NewFakeCdiClient(c, createValidDataVolume(), createNoLabelDataVolume(), createWrongPrefixDataVolume())
})

DescribeTable("GetDataVolume should return the right thing", func(volumeName string, expectedErr error) {
_, err := c.GetDataVolume(testNamespace, volumeName)
if expectedErr != nil {
Expect(err).To(Equal(expectedErr))
} else {
Expect(err).ToNot(HaveOccurred())
}
},
Entry("when the data volume exists", validDataVolume, nil),
Entry("when the data volume exists, but no labels", nolabelDataVolume, ErrInvalidVolume),
Entry("when the data volume exists, but no labels", testVolumeName, ErrInvalidVolume),
)

It("should return not exists if the data volume does not exist", func() {
_, err := c.GetDataVolume(testNamespace, "notexist")
Expect(err).To(HaveOccurred())
Expect(errors.IsNotFound(err)).To(BeTrue())
})

It("DeleteDataVolume should not delete volumes if the right prefix doesn't exist", func() {
err := c.DeleteDataVolume(testNamespace, testVolumeName)
Expect(err).To(HaveOccurred())
Expect(err).To(Equal(ErrInvalidVolume))
})

It("DeleteDataVolume return nil if volume doesn't exist", func() {
err := c.DeleteDataVolume(testNamespace, "notexist")
Expect(err).ToNot(HaveOccurred())
})

It("DeleteDataVolume should delete volumes if valid", func() {
err := c.DeleteDataVolume(testNamespace, validDataVolume)
Expect(err).ToNot(HaveOccurred())
})

It("Should create a volume if a valid volume is passed", func() {
dataVolume := createValidDataVolume()
dataVolume.Name = "pvc-test2"
_, err := c.CreateDataVolume(testNamespace, dataVolume)
Expect(err).ToNot(HaveOccurred())
})

It("Should not create a volume if an invalid volume name is passed", func() {
dataVolume := createValidDataVolume()
dataVolume.Name = "test"
_, err := c.CreateDataVolume(testNamespace, dataVolume)
Expect(err).To(Equal(ErrInvalidVolume))
})
})
})

func NewFakeCdiClient(c *client, objects ...runtime.Object) *client {
fakeCdiClient := fakecdi.NewSimpleClientset(objects...)
c.cdiClient = fakeCdiClient
return c
}

func NewFakeClient() *client {
testVolume := createPersistentVolume(testVolumeName, storageClassName)
testVolumeNotAllowed := createPersistentVolume(testVolumeNameNotAllowed, "not-allowed-storage-class")
testClaim := createPersistentVolumeClaim(testClaimName, testVolumeName, storageClassName)
testClaim2 := createPersistentVolumeClaim(testClaimName2, "testVolumeName2", storageClassName)
testClaim3 := createPersistentVolumeClaim(testClaimName3, testVolumeNameNotAllowed, "not-allowed-storage-class")
unboundClaim := &k8sv1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: unboundTestClaimName,
Namespace: testNamespace,
},
Spec: k8sv1.PersistentVolumeClaimSpec{
StorageClassName: pointer.String(storageClassName),
},
}
fakeK8sClient := k8sfake.NewSimpleClientset(testVolume, testVolumeNotAllowed, testClaim, testClaim2, testClaim3, unboundClaim)

result := &client{
kubernetesClient: fakeK8sClient,
infraLabelMap: map[string]string{"test": "test"},
volumePrefix: "pvc-",
}
return result
}

func createPersistentVolume(name, storageClassName string) *k8sv1.PersistentVolume {
return &k8sv1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: k8sv1.PersistentVolumeSpec{
StorageClassName: storageClassName,
},
}
}

func createPersistentVolumeClaim(name, volumeName, storageClassName string) *k8sv1.PersistentVolumeClaim {
return &k8sv1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: testNamespace,
Labels: map[string]string{"test": "test"},
},
Spec: k8sv1.PersistentVolumeClaimSpec{
StorageClassName: pointer.String(storageClassName),
VolumeName: volumeName,
},
}
}

func createDataVolume(name string, labels map[string]string) *cdiv1.DataVolume {
return &cdiv1.DataVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: testNamespace,
Labels: labels,
},
Spec: cdiv1.DataVolumeSpec{},
}
}

func createValidDataVolume() *cdiv1.DataVolume {
return createDataVolume(validDataVolume, map[string]string{"test": "test"})
}

func createNoLabelDataVolume() *cdiv1.DataVolume {
return createDataVolume(nolabelDataVolume, nil)
}

func createWrongPrefixDataVolume() *cdiv1.DataVolume {
return createDataVolume(testVolumeName, map[string]string{"test": "test"})
}
2 changes: 0 additions & 2 deletions vendor/github.com/fsnotify/fsnotify/.mailmap

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 001fd0b

Please sign in to comment.