api/handler/service_vm_status_test.go
Rama main · réplica de lectura del repositorio original.
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: ®istryURL,
},
},
},
},
},
},
}, 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)
}
}