Skip to content

Commit

Permalink
test(virtbmc): add unit tests for virtbmc
Browse files Browse the repository at this point in the history
Signed-off-by: Zespre Schmidt <[email protected]>
  • Loading branch information
starbops committed Oct 25, 2024
1 parent 25e2e78 commit 18cbb7e
Show file tree
Hide file tree
Showing 4 changed files with 333 additions and 1 deletion.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/onsi/ginkgo/v2 v2.11.0
github.com/onsi/gomega v1.27.10
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.2
github.com/urfave/cli/v2 v2.25.7
github.com/vmware/goipmi v0.0.0-20181114221114-2333cd82d702
k8s.io/api v0.28.3
Expand Down Expand Up @@ -50,12 +51,14 @@ require (
github.com/openshift/custom-resource-status v1.1.2 // indirect
github.com/pborman/uuid v1.2.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.25.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
Expand Down
323 changes: 323 additions & 0 deletions pkg/virtbmc/k8s_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
package virtbmc

import (
"context"
"testing"

"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
kubevirtv1 "kubevirt.io/api/core/v1"
kubevirttypev1 "kubevirt.io/kubevirtbmc/pkg/generated/clientset/versioned/typed/core/v1"
)

type MockKubevirtClient struct {
mock.Mock
}

func (m *MockKubevirtClient) VirtualMachines(namespace string) kubevirttypev1.VirtualMachineInterface {
args := m.Called(namespace)
return args.Get(0).(kubevirttypev1.VirtualMachineInterface)
}

type MockVirtualMachineInterface struct {
mock.Mock
}

func (m *MockVirtualMachineInterface) Get(
ctx context.Context, name string, options v1.GetOptions,
) (*kubevirtv1.VirtualMachine, error) {
args := m.Called(ctx, name, options)
return args.Get(0).(*kubevirtv1.VirtualMachine), args.Error(1)
}

func (m *MockVirtualMachineInterface) Create(
ctx context.Context, vm *kubevirtv1.VirtualMachine, options v1.CreateOptions,
) (*kubevirtv1.VirtualMachine, error) {
panic("implement me")
}

func (m *MockVirtualMachineInterface) Update(
ctx context.Context, vm *kubevirtv1.VirtualMachine, options v1.UpdateOptions,
) (*kubevirtv1.VirtualMachine, error) {
args := m.Called(ctx, vm, options)
return args.Get(0).(*kubevirtv1.VirtualMachine), args.Error(1)
}

func (m *MockVirtualMachineInterface) Delete(ctx context.Context, name string, options v1.DeleteOptions) error {
panic("implement me")
}

func (m *MockVirtualMachineInterface) DeleteCollection(
ctx context.Context, options v1.DeleteOptions, listOptions v1.ListOptions,
) error {
panic("implement me")
}

func (m *MockVirtualMachineInterface) List(
ctx context.Context, options v1.ListOptions,
) (*kubevirtv1.VirtualMachineList, error) {
panic("implement me")
}

func (m *MockVirtualMachineInterface) Patch(
ctx context.Context,
name string,
pt types.PatchType,
data []byte,
options v1.PatchOptions,
subresources ...string,
) (*kubevirtv1.VirtualMachine, error) {
panic("implement me")
}

func (m *MockVirtualMachineInterface) UpdateStatus(
ctx context.Context, vm *kubevirtv1.VirtualMachine, options v1.UpdateOptions,
) (*kubevirtv1.VirtualMachine, error) {
panic("implement me")
}

func (m *MockVirtualMachineInterface) Watch(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
panic("implement me")
}

func (m *MockKubevirtClient) VirtualMachineInstances(namespace string) kubevirttypev1.VirtualMachineInstanceInterface {
args := m.Called(namespace)
return args.Get(0).(kubevirttypev1.VirtualMachineInstanceInterface)
}

type MockVirtualMachineInstanceInterface struct {
mock.Mock
}

func (m *MockVirtualMachineInstanceInterface) Get(
ctx context.Context, name string, options v1.GetOptions,
) (*kubevirtv1.VirtualMachineInstance, error) {
panic("implement me")
}

func (m *MockVirtualMachineInstanceInterface) Create(
ctx context.Context, vmi *kubevirtv1.VirtualMachineInstance, options v1.CreateOptions,
) (*kubevirtv1.VirtualMachineInstance, error) {
panic("implement me")
}

func (m *MockVirtualMachineInstanceInterface) Update(
ctx context.Context, vmi *kubevirtv1.VirtualMachineInstance, options v1.UpdateOptions,
) (*kubevirtv1.VirtualMachineInstance, error) {
args := m.Called(ctx, vmi, options)
return args.Get(0).(*kubevirtv1.VirtualMachineInstance), args.Error(1)
}

func (m *MockVirtualMachineInstanceInterface) Delete(ctx context.Context, name string, options v1.DeleteOptions) error {
args := m.Called(ctx, name, options)
return args.Error(0)
}

func (m *MockVirtualMachineInstanceInterface) DeleteCollection(
ctx context.Context, options v1.DeleteOptions, listOptions v1.ListOptions,
) error {
panic("implement me")
}

func (m *MockVirtualMachineInstanceInterface) List(
ctx context.Context, options v1.ListOptions,
) (*kubevirtv1.VirtualMachineInstanceList, error) {
panic("implement me")
}

func (m *MockVirtualMachineInstanceInterface) Patch(
ctx context.Context,
name string,
pt types.PatchType,
data []byte,
options v1.PatchOptions,
subresources ...string,
) (*kubevirtv1.VirtualMachineInstance, error) {
panic("implement me")
}

func (m *MockVirtualMachineInstanceInterface) UpdateStatus(
ctx context.Context, vm *kubevirtv1.VirtualMachineInstance, options v1.UpdateOptions,
) (*kubevirtv1.VirtualMachineInstance, error) {
panic("implement me")
}

func (m *MockVirtualMachineInstanceInterface) Watch(
ctx context.Context, options v1.ListOptions,
) (watch.Interface, error) {
panic("implement me")
}

func TestGetVirtualMachinePowerStatus(t *testing.T) {
mockClient := new(MockKubevirtClient)
mockVMInterface := new(MockVirtualMachineInterface)
mockClient.On("VirtualMachines", "default").Return(mockVMInterface)

mockVM := &kubevirtv1.VirtualMachine{
Status: kubevirtv1.VirtualMachineStatus{
Ready: true,
},
}
mockVMInterface.On("Get", mock.Anything, "test-vm", mock.Anything).Return(mockVM, nil)

bmc := &VirtBMC{
context: context.TODO(),
address: "127.0.0.1",
port: 623,
vmNamespace: "default",
vmName: "test-vm",
kvClient: mockClient,
}

// Test getVirtualMachinePowerStatus
status, err := bmc.getVirtualMachinePowerStatus()
require.NoError(t, err)
require.True(t, status)

// Add another test case where the VM is not ready
mockVM.Status.Ready = false
mockVMInterface.On("Get", mock.Anything, "test-vm", mock.Anything).Return(mockVM, nil)

status, err = bmc.getVirtualMachinePowerStatus()
require.NoError(t, err)
require.False(t, status)
}

// Helper function to create a fake VM and set up common mock expectations
func setupVMTest(running bool) (*VirtBMC, *MockVirtualMachineInterface, *kubevirtv1.VirtualMachine) {
mockClient := new(MockKubevirtClient)
mockVMInterface := new(MockVirtualMachineInterface)
mockClient.On("VirtualMachines", "default").Return(mockVMInterface)

fakeVM := &kubevirtv1.VirtualMachine{
Spec: kubevirtv1.VirtualMachineSpec{
Running: func(b bool) *bool { return &b }(running),
},
}
mockVMInterface.On("Get", mock.Anything, "test-vm", mock.Anything).Return(fakeVM, nil)
mockVMInterface.On("Update", mock.Anything, fakeVM, mock.Anything).Return(fakeVM, nil)

bmc := &VirtBMC{
context: context.TODO(),
address: "127.0.0.1",
port: 623,
vmNamespace: "default",
vmName: "test-vm",
kvClient: mockClient,
}

return bmc, mockVMInterface, fakeVM
}

func TestStopVirtualMachine(t *testing.T) {
bmc, mockVMInterface, fakeVM := setupVMTest(true)

// Test stopVirtualMachine
err := bmc.stopVirtualMachine()
require.NoError(t, err)

// Assertion
mockVMInterface.AssertCalled(t, "Get", mock.Anything, "test-vm", mock.Anything)
mockVMInterface.AssertCalled(t, "Update", mock.Anything, fakeVM, mock.Anything)

require.NotNil(t, fakeVM.Spec.Running)
require.False(t, *fakeVM.Spec.Running)
}

func TestStartVirtualMachine(t *testing.T) {
bmc, mockVMInterface, fakeVM := setupVMTest(false)

// Test startVirtualMachine
err := bmc.startVirtualMachine()
require.NoError(t, err)

// Assertion
mockVMInterface.AssertCalled(t, "Get", mock.Anything, "test-vm", mock.Anything)
mockVMInterface.AssertCalled(t, "Update", mock.Anything, fakeVM, mock.Anything)

require.NotNil(t, fakeVM.Spec.Running)
require.True(t, *fakeVM.Spec.Running)
}

func TestRebootVirtualMachine(t *testing.T) {
mockClient := new(MockKubevirtClient)
mockVMIInterface := new(MockVirtualMachineInstanceInterface)
mockClient.On("VirtualMachineInstances", "default").Return(mockVMIInterface)

mockVMIInterface.On("Delete", mock.Anything, "test-vm", mock.Anything).Return(nil)

bmc := &VirtBMC{
context: context.TODO(),
address: "127.0.0.1",
port: 623,
vmNamespace: "default",
vmName: "test-vm",
kvClient: mockClient,
}

// Test rebootVirtualMachine
err := bmc.rebootVirtualMachine()
require.NoError(t, err)

// Assertion
mockVMIInterface.AssertCalled(t, "Delete", mock.Anything, "test-vm", mock.Anything)
}

func TestSetVirtualMachineBootDevice(t *testing.T) {
mockClient := new(MockKubevirtClient)
mockVMInterface := new(MockVirtualMachineInterface)
mockClient.On("VirtualMachines", "default").Return(mockVMInterface)

fakeVM := &kubevirtv1.VirtualMachine{
Spec: kubevirtv1.VirtualMachineSpec{
Template: &kubevirtv1.VirtualMachineInstanceTemplateSpec{
Spec: kubevirtv1.VirtualMachineInstanceSpec{
Domain: kubevirtv1.DomainSpec{
Devices: kubevirtv1.Devices{
Disks: []kubevirtv1.Disk{
{
Name: "disk1",
BootOrder: new(uint),
},
},
Interfaces: []kubevirtv1.Interface{
{
Name: "net1",
BootOrder: new(uint),
},
},
},
},
},
},
},
}
mockVMInterface.On("Get", mock.Anything, "test-vm", mock.Anything).Return(fakeVM, nil)
mockVMInterface.On("Update", mock.Anything, fakeVM, mock.Anything).Return(fakeVM, nil)

bmc := &VirtBMC{
context: context.TODO(),
address: "127.0.0.1",
port: 623,
vmNamespace: "default",
vmName: "test-vm",
kvClient: mockClient,
}

// Test PXE boot device
err := bmc.setVirtualMachineBootDevice(Pxe)
require.NoError(t, err)

require.Equal(t, uint(1), *fakeVM.Spec.Template.Spec.Domain.Devices.Interfaces[0].BootOrder)

// Test Disk boot device
err = bmc.setVirtualMachineBootDevice(Disk)
require.NoError(t, err)

require.Equal(t, uint(1), *fakeVM.Spec.Template.Spec.Domain.Devices.Disks[0].BootOrder)

mockVMInterface.AssertCalled(t, "Update", mock.Anything, fakeVM, mock.Anything)
}
7 changes: 6 additions & 1 deletion pkg/virtbmc/virtbmc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ type Options struct {
Port int
}

type KubeVirtClientInterface interface {
VirtualMachines(namespace string) kubevirtv1.VirtualMachineInterface
VirtualMachineInstances(namespace string) kubevirtv1.VirtualMachineInstanceInterface
}

type VirtBMC struct {
context context.Context
address string
port int
vmNamespace string
vmName string
kvClient *kubevirtv1.KubevirtV1Client
kvClient KubeVirtClientInterface
sim *ipmi.Simulator
}

Expand Down

0 comments on commit 18cbb7e

Please sign in to comment.