Ctrl K
ComunidadGuías…

api/handler/service_vm_resource_sync_test.go

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

Archivo original ↗Preguntar a KiBot
package handler

import (
	"context"
	"testing"

	apimodel "github.com/goodrain/rainbond/api/model"
	"github.com/goodrain/rainbond/db"
	dbdao "github.com/goodrain/rainbond/db/dao"
	dbmodel "github.com/goodrain/rainbond/db/model"
	mqpb "github.com/goodrain/rainbond/mq/api/grpc/pb"
	gclient "github.com/goodrain/rainbond/mq/client"
	workermodel "github.com/goodrain/rainbond/worker/discover/model"
	"google.golang.org/grpc"
)

type resourceSyncTestManager struct {
	db.Manager
	serviceDao      dbdao.TenantServiceDao
	eventDao        dbdao.EventDao
	serviceProbeDao dbdao.ServiceProbeDao
	relationDao     dbdao.TenantServiceRelationDao
	attributeDao    dbdao.ComponentK8sAttributeDao
}

func (m resourceSyncTestManager) TenantServiceDao() dbdao.TenantServiceDao {
	return m.serviceDao
}

func (m resourceSyncTestManager) ServiceEventDao() dbdao.EventDao {
	return m.eventDao
}

func (m resourceSyncTestManager) ServiceProbeDao() dbdao.ServiceProbeDao {
	return m.serviceProbeDao
}

func (m resourceSyncTestManager) TenantServiceRelationDao() dbdao.TenantServiceRelationDao {
	return m.relationDao
}

func (m resourceSyncTestManager) ComponentK8sAttributeDao() dbdao.ComponentK8sAttributeDao {
	return m.attributeDao
}

type resourceSyncTenantServiceDao struct {
	dbdao.TenantServiceDao
	service        *dbmodel.TenantServices
	updatedService *dbmodel.TenantServices
}

func (d *resourceSyncTenantServiceDao) GetServiceByID(serviceID string) (*dbmodel.TenantServices, error) {
	return d.service, nil
}

func (d *resourceSyncTenantServiceDao) IsK8sComponentNameDuplicate(appID, serviceID, k8sComponentName string) bool {
	return false
}

func (d *resourceSyncTenantServiceDao) UpdateModel(arg dbmodel.Interface) error {
	service, ok := arg.(*dbmodel.TenantServices)
	if !ok {
		return nil
	}
	copied := *service
	d.updatedService = &copied
	d.service = &copied
	return nil
}

type resourceSyncEventDao struct {
	dbdao.EventDao
	statuses []dbmodel.EventStatus
}

func (d *resourceSyncEventDao) SetEventStatus(_ context.Context, status dbmodel.EventStatus) error {
	d.statuses = append(d.statuses, status)
	return nil
}

type resourceSyncServiceProbeDao struct {
	dbdao.ServiceProbeDao
	added   int
	updated int
	deleted int
}

func (d *resourceSyncServiceProbeDao) AddModel(dbmodel.Interface) error {
	d.added++
	return nil
}

func (d *resourceSyncServiceProbeDao) UpdateModel(dbmodel.Interface) error {
	d.updated++
	return nil
}

func (d *resourceSyncServiceProbeDao) DeleteModel(string, ...interface{}) error {
	d.deleted++
	return nil
}

type resourceSyncRelationDao struct {
	dbdao.TenantServiceRelationDao
	added   int
	deleted int
}

func (d *resourceSyncRelationDao) AddModel(dbmodel.Interface) error {
	d.added++
	return nil
}

func (d *resourceSyncRelationDao) DeleteRelationByDepID(serviceID, depID string) error {
	d.deleted++
	return nil
}

type resourceSyncComponentK8sAttributeDao struct {
	dbdao.ComponentK8sAttributeDao
	attributes map[string]*dbmodel.ComponentK8sAttributes
	deleted    []string
}

func (d *resourceSyncComponentK8sAttributeDao) GetByComponentIDAndName(componentID, name string) (*dbmodel.ComponentK8sAttributes, error) {
	if d.attributes == nil {
		return nil, nil
	}
	attr := d.attributes[name]
	if attr == nil {
		return nil, nil
	}
	copied := *attr
	return &copied, nil
}

func (d *resourceSyncComponentK8sAttributeDao) UpdateModel(mo dbmodel.Interface) error {
	attr, ok := mo.(*dbmodel.ComponentK8sAttributes)
	if !ok {
		return nil
	}
	if d.attributes == nil {
		d.attributes = map[string]*dbmodel.ComponentK8sAttributes{}
	}
	copied := *attr
	d.attributes[attr.Name] = &copied
	return nil
}

func (d *resourceSyncComponentK8sAttributeDao) CreateOrUpdateAttributesInBatch(attributes []*dbmodel.ComponentK8sAttributes) error {
	if d.attributes == nil {
		d.attributes = map[string]*dbmodel.ComponentK8sAttributes{}
	}
	for _, attr := range attributes {
		copied := *attr
		d.attributes[attr.Name] = &copied
	}
	return nil
}

func (d *resourceSyncComponentK8sAttributeDao) DeleteByComponentIDAndName(componentID, name string) error {
	d.deleted = append(d.deleted, componentID+"/"+name)
	if d.attributes != nil {
		delete(d.attributes, name)
	}
	return nil
}

type noopMQClient struct{}

func (m *noopMQClient) Enqueue(context.Context, *mqpb.EnqueueRequest, ...grpc.CallOption) (*mqpb.TaskReply, error) {
	return nil, nil
}

func (m *noopMQClient) Topics(context.Context, *mqpb.TopicRequest, ...grpc.CallOption) (*mqpb.TaskReply, error) {
	return nil, nil
}

func (m *noopMQClient) Dequeue(context.Context, *mqpb.DequeueRequest, ...grpc.CallOption) (*mqpb.TaskMessage, error) {
	return nil, nil
}

func (m *noopMQClient) Close() {}

func (m *noopMQClient) SendBuilderTopic(gclient.TaskStruct) error {
	return nil
}

// capability_id: rainbond.vm-probe-change-syncs-spec
func TestServiceProbeSyncsVirtualMachineSpecWhenVMProbeChanges(t *testing.T) {
	for _, tc := range []struct {
		name       string
		action     string
		wantAdd    int
		wantUpdate int
		wantDelete int
	}{
		{name: "add", action: "add", wantAdd: 1},
		{name: "update", action: "update", wantUpdate: 1},
		{name: "delete", action: "delete", wantDelete: 1},
	} {
		t.Run(tc.name, func(t *testing.T) {
			serviceDao := &resourceSyncTenantServiceDao{
				service: &dbmodel.TenantServices{
					ServiceID:    "service-vm",
					ServiceAlias: "service-vm",
					ExtendMethod: "vm",
				},
			}
			probeDao := &resourceSyncServiceProbeDao{}
			db.SetTestManager(resourceSyncTestManager{
				serviceDao:      serviceDao,
				eventDao:        &resourceSyncEventDao{},
				serviceProbeDao: probeDao,
			})
			defer db.SetTestManager(nil)

			syncedServiceID := ""
			action := &ServiceAction{
				syncVirtualMachineSpecHook: func(serviceID string) error {
					syncedServiceID = serviceID
					return nil
				},
			}

			err := action.ServiceProbe(&dbmodel.TenantServiceProbe{
				ServiceID: "service-vm",
				ProbeID:   "probe-vm",
				Mode:      "readiness",
			}, tc.action)
			if err != nil {
				t.Fatalf("expected no error, got %v", err)
			}
			if syncedServiceID != "service-vm" {
				t.Fatalf("expected vm spec sync for service-vm, got %q", syncedServiceID)
			}
			if probeDao.added != tc.wantAdd || probeDao.updated != tc.wantUpdate || probeDao.deleted != tc.wantDelete {
				t.Fatalf("unexpected probe dao calls: add=%d update=%d delete=%d", probeDao.added, probeDao.updated, probeDao.deleted)
			}
		})
	}
}

func TestServiceUpdateSyncsVirtualMachineSpecWhenVMResourcesChange(t *testing.T) {
	serviceDao := &resourceSyncTenantServiceDao{
		service: &dbmodel.TenantServices{
			ServiceID:        "service-vm",
			ServiceAlias:     "service-vm",
			ExtendMethod:     "vm",
			ContainerCPU:     500,
			ContainerMemory:  512,
			ContainerGPU:     0,
			K8sComponentName: "demo-vm",
		},
	}
	db.SetTestManager(resourceSyncTestManager{
		serviceDao: serviceDao,
		eventDao:   &resourceSyncEventDao{},
	})
	defer db.SetTestManager(nil)

	syncedServiceID := ""
	action := &ServiceAction{
		syncVirtualMachineSpecHook: func(serviceID string) error {
			syncedServiceID = serviceID
			return nil
		},
	}

	err := action.ServiceUpdate(map[string]interface{}{
		"service_id":         "service-vm",
		"container_cpu":      1000,
		"container_memory":   1024,
		"k8s_component_name": "demo-vm",
	})
	if err != nil {
		t.Fatalf("expected no error, got %v", err)
	}
	if syncedServiceID != "service-vm" {
		t.Fatalf("expected vm spec sync for service-vm, got %q", syncedServiceID)
	}
	if serviceDao.updatedService == nil {
		t.Fatal("expected updated service to be persisted")
	}
	if serviceDao.updatedService.ContainerCPU != 1000 || serviceDao.updatedService.ContainerMemory != 1024 {
		t.Fatalf("expected updated resources to be persisted, got cpu=%d mem=%d", serviceDao.updatedService.ContainerCPU, serviceDao.updatedService.ContainerMemory)
	}
}

func TestServiceVerticalSyncsVirtualMachineSpecWhenVMResourcesChange(t *testing.T) {
	serviceDao := &resourceSyncTenantServiceDao{
		service: &dbmodel.TenantServices{
			ServiceID:       "service-vm",
			ServiceAlias:    "service-vm",
			ExtendMethod:    "vm",
			ContainerCPU:    500,
			ContainerMemory: 512,
			ContainerGPU:    0,
		},
	}
	db.SetTestManager(resourceSyncTestManager{
		serviceDao: serviceDao,
		eventDao:   &resourceSyncEventDao{},
	})
	defer db.SetTestManager(nil)

	syncedServiceID := ""
	cpu := 1000
	memory := 1024
	action := &ServiceAction{
		MQClient: &noopMQClient{},
		syncVirtualMachineSpecHook: func(serviceID string) error {
			syncedServiceID = serviceID
			return nil
		},
	}

	err := action.ServiceVertical(context.Background(), &workermodel.VerticalScalingTaskBody{
		ServiceID:       "service-vm",
		ContainerCPU:    &cpu,
		ContainerMemory: &memory,
	})
	if err != nil {
		t.Fatalf("expected no error, got %v", err)
	}
	if syncedServiceID != "service-vm" {
		t.Fatalf("expected vm spec sync for service-vm, got %q", syncedServiceID)
	}
	if serviceDao.updatedService == nil {
		t.Fatal("expected updated service to be persisted")
	}
	if serviceDao.updatedService.ContainerCPU != 1000 || serviceDao.updatedService.ContainerMemory != 1024 {
		t.Fatalf("expected updated resources to be persisted, got cpu=%d mem=%d", serviceDao.updatedService.ContainerCPU, serviceDao.updatedService.ContainerMemory)
	}
}

func TestServiceDependSyncsVirtualMachineSpecWhenVMDependencyChanges(t *testing.T) {
	for _, tc := range []struct {
		name   string
		action string
	}{
		{name: "add", action: "add"},
		{name: "delete", action: "delete"},
	} {
		t.Run(tc.name, func(t *testing.T) {
			serviceDao := &resourceSyncTenantServiceDao{
				service: &dbmodel.TenantServices{
					ServiceID:    "service-vm",
					ServiceAlias: "service-vm",
					ExtendMethod: "vm",
				},
			}
			db.SetTestManager(resourceSyncTestManager{
				serviceDao:  serviceDao,
				eventDao:    &resourceSyncEventDao{},
				relationDao: &resourceSyncRelationDao{},
			})
			defer db.SetTestManager(nil)

			syncedServiceID := ""
			action := &ServiceAction{
				syncVirtualMachineSpecHook: func(serviceID string) error {
					syncedServiceID = serviceID
					return nil
				},
			}

			err := action.ServiceDepend(tc.action, &apimodel.DependService{
				TenantID:     "tenant-1",
				ServiceID:    "service-vm",
				DepServiceID: "dep-service",
			})
			if err != nil {
				t.Fatalf("expected no error, got %v", err)
			}
			if syncedServiceID != "service-vm" {
				t.Fatalf("expected vm spec sync for service-vm, got %q", syncedServiceID)
			}
		})
	}
}