Ctrl K
ComunidadGuías…

api/handler/service_vm_status_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package handler

import (
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	kubevirtv1 "kubevirt.io/api/core/v1"
	cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
)

// capability_id: rainbond.vm-template-import.status-restoring
func TestResolveVMTransitionStatusReturnsStartingForDataVolumeImportWithoutRestoreContext(t *testing.T) {
	vm := &kubevirtv1.VirtualMachine{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "demo-vm",
			Namespace: "demo-ns",
		},
		Status: kubevirtv1.VirtualMachineStatus{
			PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
		},
	}
	vmi := &kubevirtv1.VirtualMachineInstance{
		Status: kubevirtv1.VirtualMachineInstanceStatus{
			Phase: kubevirtv1.Pending,
			Conditions: []kubevirtv1.VirtualMachineInstanceCondition{
				{
					Type:   kubevirtv1.VirtualMachineInstanceProvisioning,
					Status: "True",
				},
				{
					Type:   kubevirtv1.VirtualMachineInstanceDataVolumesReady,
					Status: "False",
				},
			},
		},
	}

	got, ok := resolveVMTransitionStatus(vm, vmi)
	if !ok {
		t.Fatal("expected importing data volumes to override vm closed status")
	}
	if got != "starting" {
		t.Fatalf("expected importing data volumes without restore context to map to %q, got %q", "starting", got)
	}
}

// capability_id: rainbond.vm-template-import.status-restoring
func TestResolveVMServiceRuntimeStatusReturnsRestoringWhenArtifactDataVolumeImportsBeforeVMIExists(t *testing.T) {
	action := &ServiceAction{
		getVirtualMachineByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachine, error) {
			return &kubevirtv1.VirtualMachine{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "demo-vm",
					Namespace: "demo-ns",
				},
				Spec: kubevirtv1.VirtualMachineSpec{
					DataVolumeTemplates: []kubevirtv1.DataVolumeTemplateSpec{
						{
							ObjectMeta: metav1.ObjectMeta{
								Name: "manual133",
								Annotations: map[string]string{
									"rainbond.com/vm-artifact-image":   "goodrain.me/team/windows-root:v1",
									"rainbond.com/vm-artifact-service": "vm-artifact-manual133",
								},
							},
						},
					},
				},
				Status: kubevirtv1.VirtualMachineStatus{
					PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
				},
			}, nil
		},
		getVirtualMachineInstanceByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachineInstance, error) {
			return nil, nil
		},
		getDataVolumePhasesByNamesHook: func(namespace string, names []string) (map[string]string, error) {
			if namespace != "demo-ns" {
				t.Fatalf("expected namespace %q, got %q", "demo-ns", namespace)
			}
			if len(names) != 1 || names[0] != "manual133" {
				t.Fatalf("expected data volume names [manual133], got %#v", names)
			}
			return map[string]string{
				"manual133": "ImportInProgress",
			}, nil
		},
	}

	got, ok := action.resolveVMServiceRuntimeStatus("service-a")
	if !ok {
		t.Fatal("expected importing data volume to override vm status before vmi exists")
	}
	if got != "restoring" {
		t.Fatalf("expected importing data volume to map to %q, got %q", "restoring", got)
	}
}

// capability_id: rainbond.vm-template-import.status-restoring
func TestResolveVMServiceRuntimeStatusReturnsStartingForInitialBlankDataVolume(t *testing.T) {
	action := &ServiceAction{
		getVirtualMachineByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachine, error) {
			return &kubevirtv1.VirtualMachine{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "demo-vm",
					Namespace: "demo-ns",
				},
				Spec: kubevirtv1.VirtualMachineSpec{
					DataVolumeTemplates: []kubevirtv1.DataVolumeTemplateSpec{
						{
							ObjectMeta: metav1.ObjectMeta{
								Name: "manual133",
							},
							Spec: cdiv1.DataVolumeSpec{
								Source: &cdiv1.DataVolumeSource{
									Blank: &cdiv1.DataVolumeBlankImage{},
								},
							},
						},
					},
				},
				Status: kubevirtv1.VirtualMachineStatus{
					PrintableStatus: kubevirtv1.VirtualMachineStatusProvisioning,
				},
			}, nil
		},
		getVirtualMachineInstanceByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachineInstance, error) {
			return nil, nil
		},
		getDataVolumePhasesByNamesHook: func(namespace string, names []string) (map[string]string, error) {
			t.Fatalf("blank data volumes should not be queried as restore volumes")
			return nil, nil
		},
	}

	got, ok := action.resolveVMServiceRuntimeStatus("service-a")
	if !ok {
		t.Fatal("expected provisioning vm to map to starting")
	}
	if got != "starting" {
		t.Fatalf("expected initial blank data volume to map to %q, got %q", "starting", got)
	}
}

// capability_id: rainbond.vm-template-import.status-restoring
func TestResolveVMServiceRuntimeStatusReturnsStartingForInitialHTTPDataVolume(t *testing.T) {
	action := &ServiceAction{
		getVirtualMachineByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachine, error) {
			return &kubevirtv1.VirtualMachine{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "demo-vm",
					Namespace: "demo-ns",
				},
				Spec: kubevirtv1.VirtualMachineSpec{
					DataVolumeTemplates: []kubevirtv1.DataVolumeTemplateSpec{
						{
							ObjectMeta: metav1.ObjectMeta{
								Name: "manual133",
							},
							Spec: cdiv1.DataVolumeSpec{
								Source: &cdiv1.DataVolumeSource{
									HTTP: &cdiv1.DataVolumeSourceHTTP{URL: "https://download/root.qcow2"},
								},
							},
						},
					},
				},
				Status: kubevirtv1.VirtualMachineStatus{
					PrintableStatus: kubevirtv1.VirtualMachineStatusProvisioning,
				},
			}, nil
		},
		getVirtualMachineInstanceByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachineInstance, error) {
			return nil, nil
		},
		getDataVolumePhasesByNamesHook: func(namespace string, names []string) (map[string]string, error) {
			t.Fatalf("initial http data volumes should not be queried as restore volumes")
			return nil, nil
		},
	}

	got, ok := action.resolveVMServiceRuntimeStatus("service-a")
	if !ok {
		t.Fatal("expected provisioning vm to map to starting")
	}
	if got != "starting" {
		t.Fatalf("expected initial http data volume to map to %q, got %q", "starting", got)
	}
}

// capability_id: rainbond.vm-template-import.restore-progress
func TestResolveVMRestoreStatusIncludesDataVolumeProgress(t *testing.T) {
	status := resolveVMDataVolumeRestoreStatus("demo-ns", []vmDataVolumeDetail{
		{
			Name:     "manual133",
			Phase:    "ImportInProgress",
			Progress: "11.34%",
			Message:  "copying disk",
		},
		{
			Name:     "manual134",
			Phase:    "Succeeded",
			Progress: "100.0%",
		},
	})

	if status == nil {
		t.Fatal("expected restore status")
	}
	if status.Status != "restoring" {
		t.Fatalf("expected restore status %q, got %q", "restoring", status.Status)
	}
	if status.Progress != "11.34%" {
		t.Fatalf("expected aggregate progress %q, got %q", "11.34%", status.Progress)
	}
	if len(status.DataVolumes) != 2 {
		t.Fatalf("expected two data volumes, got %#v", status.DataVolumes)
	}
	if len(status.ImporterPods) != 1 || status.ImporterPods[0].Name != "importer-manual133" {
		t.Fatalf("expected importer pod for importing volume, got %#v", status.ImporterPods)
	}
	if status.Message != "manual133: copying disk" {
		t.Fatalf("expected restore message from importing volume, got %q", status.Message)
	}
}

// capability_id: rainbond.vm-template-import.restore-progress
func TestResolveVMRestoreStatusMarksAllDataVolumesSucceeded(t *testing.T) {
	status := resolveVMDataVolumeRestoreStatus("demo-ns", []vmDataVolumeDetail{
		{
			Name:     "manual133",
			Phase:    "Succeeded",
			Progress: "100.0%",
		},
	})

	if status == nil {
		t.Fatal("expected restore status")
	}
	if status.Status != "success" {
		t.Fatalf("expected restore status %q, got %q", "success", status.Status)
	}
	if status.Progress != "100.0%" {
		t.Fatalf("expected progress 100.0%%, got %q", status.Progress)
	}
	if len(status.ImporterPods) != 0 {
		t.Fatalf("expected no importer pods after success, got %#v", status.ImporterPods)
	}
}

// capability_id: rainbond.vm-template-import.restore-progress
func TestResolveVMDataVolumeRestoreIgnoresInitialBlankDataVolumes(t *testing.T) {
	action := &ServiceAction{
		getVirtualMachineByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachine, error) {
			return &kubevirtv1.VirtualMachine{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "demo-vm",
					Namespace: "demo-ns",
				},
				Spec: kubevirtv1.VirtualMachineSpec{
					DataVolumeTemplates: []kubevirtv1.DataVolumeTemplateSpec{
						{
							ObjectMeta: metav1.ObjectMeta{
								Name: "manual133",
							},
							Spec: cdiv1.DataVolumeSpec{
								Source: &cdiv1.DataVolumeSource{
									Blank: &cdiv1.DataVolumeBlankImage{},
								},
							},
						},
					},
				},
			}, nil
		},
		getDataVolumeDetailsByNamesHook: func(namespace string, names []string) ([]vmDataVolumeDetail, error) {
			t.Fatalf("blank data volumes should not be queried as restore details")
			return nil, nil
		},
	}

	if got := action.resolveVMDataVolumeRestore("service-a"); got != nil {
		t.Fatalf("expected no restore status for initial blank data volume, got %#v", got)
	}
}

// capability_id: rainbond.vm-template-import.registry-restore-progress
func TestResolveVMDataVolumeRestoreIncludesRegistryImportDataVolumes(t *testing.T) {
	registryURL := "docker://goodrain.me/ceshi:test-zqh"
	action := &ServiceAction{
		getVirtualMachineByServiceIDHook: func(serviceID string) (*kubevirtv1.VirtualMachine, error) {
			return &kubevirtv1.VirtualMachine{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "test-zqh",
					Namespace: "ceshi",
				},
				Spec: kubevirtv1.VirtualMachineSpec{
					DataVolumeTemplates: []kubevirtv1.DataVolumeTemplateSpec{
						{
							ObjectMeta: metav1.ObjectMeta{
								Name: "manual-root",
							},
							Spec: cdiv1.DataVolumeSpec{
								Source: &cdiv1.DataVolumeSource{
									Registry: &cdiv1.DataVolumeSourceRegistry{
										URL: &registryURL,
									},
								},
							},
						},
					},
				},
			}, nil
		},
		getDataVolumeDetailsByNamesHook: func(namespace string, names []string) ([]vmDataVolumeDetail, error) {
			if namespace != "ceshi" {
				t.Fatalf("expected namespace ceshi, got %q", namespace)
			}
			if len(names) != 1 || names[0] != "manual-root" {
				t.Fatalf("expected registry import data volume manual-root, got %#v", names)
			}
			return []vmDataVolumeDetail{
				{
					Name:     "manual-root",
					Phase:    "Failed",
					Progress: "N/A",
					Message:  "pull image failed",
				},
			}, nil
		},
	}

	status := action.resolveVMDataVolumeRestore("service-a")
	if status == nil {
		t.Fatal("expected registry import data volume restore status")
	}
	if status.Status != "failure" {
		t.Fatalf("expected failure restore status, got %q", status.Status)
	}
	if status.Message != "manual-root: pull image failed" {
		t.Fatalf("expected registry import failure message, got %q", status.Message)
	}
}

func TestResolveVMTransitionStatusReturnsStartingForPendingProvisioningVMI(t *testing.T) {
	vm := &kubevirtv1.VirtualMachine{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "demo-vm",
			Namespace: "demo-ns",
		},
		Status: kubevirtv1.VirtualMachineStatus{
			PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
		},
	}
	vmi := &kubevirtv1.VirtualMachineInstance{
		Status: kubevirtv1.VirtualMachineInstanceStatus{
			Phase: kubevirtv1.Pending,
			Conditions: []kubevirtv1.VirtualMachineInstanceCondition{
				{
					Type:   kubevirtv1.VirtualMachineInstanceProvisioning,
					Status: "True",
				},
			},
		},
	}

	got, ok := resolveVMTransitionStatus(vm, vmi)
	if !ok {
		t.Fatal("expected pending provisioning vmi to override vm closed status")
	}
	if got != "starting" {
		t.Fatalf("expected pending provisioning vmi to map to %q, got %q", "starting", got)
	}
}

func TestResolveVMTransitionStatusKeepsStoppedVMClosedWhenNoVMIExists(t *testing.T) {
	vm := &kubevirtv1.VirtualMachine{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "demo-vm",
			Namespace: "demo-ns",
		},
		Status: kubevirtv1.VirtualMachineStatus{
			PrintableStatus: kubevirtv1.VirtualMachineStatusStopped,
		},
	}

	if got, ok := resolveVMTransitionStatus(vm, nil); ok {
		t.Fatalf("expected no override for stopped vm without vmi, got status %q", got)
	}
}

func TestResolveVMTransitionStatusReturnsAbnormalForDataVolumeError(t *testing.T) {
	vm := &kubevirtv1.VirtualMachine{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "demo-vm",
			Namespace: "demo-ns",
		},
		Status: kubevirtv1.VirtualMachineStatus{
			PrintableStatus: kubevirtv1.VirtualMachineStatusDataVolumeError,
		},
	}

	got, ok := resolveVMTransitionStatus(vm, nil)
	if !ok {
		t.Fatal("expected data volume error to override vm status")
	}
	if got != "abnormal" {
		t.Fatalf("expected data volume error to map to %q, got %q", "abnormal", got)
	}
}