api/handler/service_vm_power_test.go
Rama main · réplica de lectura del repositorio original.
// capability_id: rainbond.vm-power.start-existing-or-create
// capability_id: rainbond.vm-power.direct-ops-event-close
// capability_id: rainbond.vm-power.stop-restoring-fallback
package handler
import (
"context"
"errors"
"testing"
"github.com/golang/mock/gomock"
apimodel "github.com/goodrain/rainbond/api/model"
ctxutil "github.com/goodrain/rainbond/api/util/ctx"
"github.com/goodrain/rainbond/db"
dbmodel "github.com/goodrain/rainbond/db/model"
mqpb "github.com/goodrain/rainbond/mq/api/grpc/pb"
mqclient "github.com/goodrain/rainbond/mq/client"
"google.golang.org/grpc"
k8sapierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
kubevirtv1 "kubevirt.io/api/core/v1"
kubecli "kubevirt.io/client-go/kubecli"
)
type recordingMQClient struct {
tasks []mqclient.TaskStruct
}
func (m *recordingMQClient) Enqueue(context.Context, *mqpb.EnqueueRequest, ...grpc.CallOption) (*mqpb.TaskReply, error) {
return nil, nil
}
func (m *recordingMQClient) Topics(context.Context, *mqpb.TopicRequest, ...grpc.CallOption) (*mqpb.TaskReply, error) {
return nil, nil
}
func (m *recordingMQClient) Dequeue(context.Context, *mqpb.DequeueRequest, ...grpc.CallOption) (*mqpb.TaskMessage, error) {
return nil, nil
}
func (m *recordingMQClient) Close() {}
func (m *recordingMQClient) SendBuilderTopic(t mqclient.TaskStruct) error {
m.tasks = append(m.tasks, t)
return nil
}
func newVMOperationEventContext(eventID string) context.Context {
return context.WithValue(context.Background(), ctxutil.ContextKey("event"), &dbmodel.ServiceEvent{EventID: eventID})
}
func TestStartOrCreateVMStartsExistingStoppedVM(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
mq := &recordingMQClient{}
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{MQClient: mq, kubevirtClient: mockClient}
err := action.StartOrCreateVM(context.Background(), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(mq.tasks) != 0 {
t.Fatalf("expected no worker start task, got %#v", mq.tasks)
}
}
func TestStartOrCreateVMStartsExistingStoppedVMWhenSpecSyncFindsMissingRootImport(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{
kubevirtClient: mockClient,
syncVirtualMachineSpecHook: func(serviceID string) error {
return errors.New("validate vm boot path failure: missing imported root data volume for vm boot source format \"qcow2\"")
},
getVirtualMachineByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachine, error) {
return &kubevirtv1.VirtualMachine{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
},
}, nil
},
}
err := action.StartOrCreateVM(context.Background(), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected existing legacy vm to start despite missing root import sync error, got %v", err)
}
}
func TestStartOrCreateVMStartsStoppedAlwaysRunStrategyVM(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
eventDao := &resourceSyncEventDao{}
db.SetTestManager(resourceSyncTestManager{eventDao: eventDao})
defer db.SetTestManager(nil)
runStrategy := kubevirtv1.RunStrategyAlways
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Spec: kubevirtv1.VirtualMachineSpec{
RunStrategy: &runStrategy,
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StartOrCreateVM(newVMOperationEventContext("event-1"), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected stopped Always run strategy VM to start, got %v", err)
}
if len(eventDao.statuses) != 1 || eventDao.statuses[0] != dbmodel.EventStatusSuccess {
t.Fatalf("expected success event status update, got %#v", eventDao.statuses)
}
}
func TestStartOrCreateVMStartsExistingVMWithUnknownPrintableStatus(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StartOrCreateVM(context.Background(), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected VM with unknown printable status to start, got %v", err)
}
}
func TestStartOrCreateVMMarksDirectStartEventSuccess(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
eventDao := &resourceSyncEventDao{}
db.SetTestManager(resourceSyncTestManager{eventDao: eventDao})
defer db.SetTestManager(nil)
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StartOrCreateVM(newVMOperationEventContext("event-1"), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(eventDao.statuses) != 1 || eventDao.statuses[0] != dbmodel.EventStatusSuccess {
t.Fatalf("expected success event status update, got %#v", eventDao.statuses)
}
}
func TestStartOrCreateVMMarksDirectStartEventFailure(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
eventDao := &resourceSyncEventDao{}
db.SetTestManager(resourceSyncTestManager{eventDao: eventDao})
defer db.SetTestManager(nil)
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(errors.New("boom"))
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StartOrCreateVM(newVMOperationEventContext("event-1"), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err == nil {
t.Fatal("expected direct VM start failure to be returned")
}
if len(eventDao.statuses) != 1 || eventDao.statuses[0] != dbmodel.EventStatusFailure {
t.Fatalf("expected failure event status update, got %#v", eventDao.statuses)
}
}
func TestStartOrCreateVMTreatsTransientStartConflictAsSuccessAfterRefresh(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
eventDao := &resourceSyncEventDao{}
db.SetTestManager(resourceSyncTestManager{eventDao: eventDao})
defer db.SetTestManager(nil)
originalDelay := vmStartRetryDelay
vmStartRetryDelay = 0
defer func() {
vmStartRetryDelay = originalDelay
}()
gomock.InOrder(
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface),
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
},
},
},
}, nil),
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface),
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(
k8sapierrors.NewConflict(schema.GroupResource{Group: "kubevirt.io", Resource: "virtualmachines"}, "demo-vm", errors.New("conflict")),
),
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface),
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStarting,
},
},
},
}, nil),
)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StartOrCreateVM(newVMOperationEventContext("event-1"), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected transient conflict to be treated as success after refresh, got %v", err)
}
if len(eventDao.statuses) != 1 || eventDao.statuses[0] != dbmodel.EventStatusSuccess {
t.Fatalf("expected success event status update, got %#v", eventDao.statuses)
}
}
func TestStartOrCreateVMFallsBackToWorkerStartWhenVMIsMissing(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
mq := &recordingMQClient{}
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{}, nil)
action := &ServiceAction{MQClient: mq, kubevirtClient: mockClient}
err := action.StartOrCreateVM(context.Background(), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "start",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(mq.tasks) != 1 {
t.Fatalf("expected one worker start task, got %#v", mq.tasks)
}
if mq.tasks[0].TaskType != "start" {
t.Fatalf("expected worker task type start, got %q", mq.tasks[0].TaskType)
}
}
func TestStopVMStopsExistingVMWithoutWorkerTask(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
mq := &recordingMQClient{}
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Stop(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{MQClient: mq, kubevirtClient: mockClient}
err := action.StopVM(context.Background(), "service-1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(mq.tasks) != 0 {
t.Fatalf("expected no worker stop task, got %#v", mq.tasks)
}
}
func TestStopVMMarksDirectStopEventSuccess(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
eventDao := &resourceSyncEventDao{}
db.SetTestManager(resourceSyncTestManager{eventDao: eventDao})
defer db.SetTestManager(nil)
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusRunning,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Stop(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StopVM(newVMOperationEventContext("event-1"), "service-1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(eventDao.statuses) != 1 || eventDao.statuses[0] != dbmodel.EventStatusSuccess {
t.Fatalf("expected success event status update, got %#v", eventDao.statuses)
}
}
func TestStopVMFallsBackToHaltingProvisioningVMWhenDirectStopFails(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMList := kubecli.NewMockVirtualMachineInterface(ctrl)
mockVMUpdate := kubecli.NewMockVirtualMachineInterface(ctrl)
gomock.InOrder(
mockClient.EXPECT().VirtualMachine("").Return(mockVMList),
mockVMList.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Spec: kubevirtv1.VirtualMachineSpec{
RunStrategy: pointerToRunStrategy(kubevirtv1.RunStrategyAlways),
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusProvisioning,
},
},
},
}, nil),
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMUpdate),
mockVMUpdate.EXPECT().Stop(gomock.Any(), "demo-vm", gomock.Any()).Return(errors.New("stop not allowed while provisioning")),
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMUpdate),
mockVMUpdate.EXPECT().Update(gomock.Any(), gomock.AssignableToTypeOf(&kubevirtv1.VirtualMachine{}), gomock.Any()).DoAndReturn(
func(_ context.Context, vm *kubevirtv1.VirtualMachine, _ metav1.UpdateOptions) (*kubevirtv1.VirtualMachine, error) {
if vm.Spec.RunStrategy == nil || *vm.Spec.RunStrategy != kubevirtv1.RunStrategyHalted {
t.Fatalf("expected fallback update to halt vm, got %#v", vm.Spec.RunStrategy)
}
if vm.Spec.Running != nil {
t.Fatalf("expected fallback update to clear legacy running flag, got %#v", vm.Spec.Running)
}
return vm, nil
},
),
)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StopVM(context.Background(), "service-1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
}
func TestStopVMFallsBackToHaltingDataVolumeErrorVMWhenDirectStopFails(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMList := kubecli.NewMockVirtualMachineInterface(ctrl)
mockVMUpdate := kubecli.NewMockVirtualMachineInterface(ctrl)
gomock.InOrder(
mockClient.EXPECT().VirtualMachine("").Return(mockVMList),
mockVMList.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Spec: kubevirtv1.VirtualMachineSpec{
RunStrategy: pointerToRunStrategy(kubevirtv1.RunStrategyAlways),
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusDataVolumeError,
},
},
},
}, nil),
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMUpdate),
mockVMUpdate.EXPECT().Stop(gomock.Any(), "demo-vm", gomock.Any()).Return(errors.New("stop not allowed while datavolume error")),
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMUpdate),
mockVMUpdate.EXPECT().Update(gomock.Any(), gomock.AssignableToTypeOf(&kubevirtv1.VirtualMachine{}), gomock.Any()).DoAndReturn(
func(_ context.Context, vm *kubevirtv1.VirtualMachine, _ metav1.UpdateOptions) (*kubevirtv1.VirtualMachine, error) {
if vm.Spec.RunStrategy == nil || *vm.Spec.RunStrategy != kubevirtv1.RunStrategyHalted {
t.Fatalf("expected fallback update to halt vm, got %#v", vm.Spec.RunStrategy)
}
return vm, nil
},
),
)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.StopVM(context.Background(), "service-1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
}
func TestRestartVMRestartsExistingRunningVMWithoutWorkerTask(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
mq := &recordingMQClient{}
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusRunning,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Restart(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{MQClient: mq, kubevirtClient: mockClient}
err := action.RestartVM(context.Background(), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "restart",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(mq.tasks) != 0 {
t.Fatalf("expected no worker restart task, got %#v", mq.tasks)
}
}
func TestRestartVMMarksDirectRestartEventSuccess(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
eventDao := &resourceSyncEventDao{}
db.SetTestManager(resourceSyncTestManager{eventDao: eventDao})
defer db.SetTestManager(nil)
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusRunning,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Restart(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{kubevirtClient: mockClient}
err := action.RestartVM(newVMOperationEventContext("event-1"), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "restart",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(eventDao.statuses) != 1 || eventDao.statuses[0] != dbmodel.EventStatusSuccess {
t.Fatalf("expected success event status update, got %#v", eventDao.statuses)
}
}
func TestRestartVMStartsStoppedVMWithoutWorkerTask(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockClient := kubecli.NewMockKubevirtClient(ctrl)
mockVMInterface := kubecli.NewMockVirtualMachineInterface(ctrl)
mq := &recordingMQClient{}
mockClient.EXPECT().VirtualMachine("").Return(mockVMInterface)
mockVMInterface.EXPECT().List(gomock.Any(), metav1.ListOptions{LabelSelector: "service_id=service-1"}).Return(&kubevirtv1.VirtualMachineList{
Items: []kubevirtv1.VirtualMachine{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-vm",
Namespace: "demo-ns",
},
Status: kubevirtv1.VirtualMachineStatus{
PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
},
},
},
}, nil)
mockClient.EXPECT().VirtualMachine("demo-ns").Return(mockVMInterface)
mockVMInterface.EXPECT().Start(gomock.Any(), "demo-vm", gomock.Any()).Return(nil)
action := &ServiceAction{MQClient: mq, kubevirtClient: mockClient}
err := action.RestartVM(context.Background(), &apimodel.StartStopStruct{
TenantID: "tenant-1",
ServiceID: "service-1",
EventID: "event-1",
TaskType: "restart",
}, "deploy-v1")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if len(mq.tasks) != 0 {
t.Fatalf("expected no worker restart task, got %#v", mq.tasks)
}
}