diff --git a/api/Control.go b/api/Control.go index 6b1a3ff..74bdcd6 100755 --- a/api/Control.go +++ b/api/Control.go @@ -95,8 +95,6 @@ func (i *InstHandler) DeleteVM(w http.ResponseWriter, r *http.Request) { i.Logger.Error("failed to delete domain", zap.String("uuid", param.UUID), zap.Error(ERR)) return } - // stat.( map[domainStatus.SourceType]int )[domainStatus.CPU] - // interface{}로 반환하다보니 좀 못생겨졌는데, 나중에 타입 결정하고 변경하면 될 거 같음, 일단은 이렇게 구현 i.DomainControl.DeleteDomain(domain.Domain, param.UUID, int(stat.(map[domainStatus.SourceType]int)[domainStatus.CPU])) resp.ResponseWriteOK(w, nil) diff --git a/api/status.go b/api/status.go index 4a83239..7bf7ff9 100755 --- a/api/status.go +++ b/api/status.go @@ -31,9 +31,9 @@ func (i *InstHandler) ReturnStatusUUID(w http.ResponseWriter, r *http.Request) { resp.ResponseWriteErr(w, virerr.ErrorJoin(err, errors.New("error returning status from uuid")), http.StatusInternalServerError) } - DomainDetail := status.DomainDetailFactory(outputStruct, dom) + DomainDetail := status.DomainDetailFactory(outputStruct, dom.Domain) - if err := outputStruct.GetInfo(dom); err != nil { + if err := outputStruct.GetInfo(dom.Domain); err != nil { resp.ResponseWriteErr(w, err, http.StatusInternalServerError) return } diff --git a/vm/service/status/Status.go b/vm/service/status/Status.go index c4ffe1f..7445c40 100755 --- a/vm/service/status/Status.go +++ b/vm/service/status/Status.go @@ -1,7 +1,6 @@ package status import ( - domCon "github.com/easy-cloud-Knet/KWS_Core/DomCon" domStatus "github.com/easy-cloud-Knet/KWS_Core/DomCon/domainList_status" "libvirt.org/go/libvirt" ) @@ -87,7 +86,7 @@ type InstDetail struct { } type InstDataTypeHandler interface { - GetAllinstInfo(LibvirtInst *libvirt.Connect) error + GetAllinstInfo(LibvirtInst Connect) error } const ( @@ -128,10 +127,10 @@ type DomainInfo struct { } type DataTypeHandler interface { - GetInfo(*domCon.Domain) error + GetInfo(Domain) error } type DomainDetail struct { DataHandle DataTypeHandler - Domain *domCon.Domain + Domain Domain } diff --git a/vm/service/status/domain.go b/vm/service/status/domain.go new file mode 100644 index 0000000..994f56c --- /dev/null +++ b/vm/service/status/domain.go @@ -0,0 +1,17 @@ +package status + +import "libvirt.org/go/libvirt" + +// Domain is a minimal interface over *libvirt.Domain for status service. +// *libvirt.Domain satisfies this via structural typing. +type Domain interface { + GetInfo() (*libvirt.DomainInfo, error) + GetState() (libvirt.DomainState, int, error) + GetUUID() ([]byte, error) + GetGuestInfo(types libvirt.DomainGuestInfoTypes, flags uint32) (*libvirt.DomainGuestInfo, error) +} + +// Connect is a minimal interface over *libvirt.Connect for listing all domains. +type Connect interface { + ListAllDomains(flags libvirt.ConnectListAllDomainsFlags) ([]libvirt.Domain, error) +} diff --git a/vm/service/status/domain_status.go b/vm/service/status/domain_status.go index 278c11f..5569e92 100755 --- a/vm/service/status/domain_status.go +++ b/vm/service/status/domain_status.go @@ -4,14 +4,13 @@ import ( "errors" "fmt" - domCon "github.com/easy-cloud-Knet/KWS_Core/DomCon" virerr "github.com/easy-cloud-Knet/KWS_Core/error" "github.com/google/uuid" "libvirt.org/go/libvirt" ) -func (DI *DomainInfo) GetInfo(domain *domCon.Domain) error { - info, err := domain.Domain.GetInfo() +func (DI *DomainInfo) GetInfo(domain Domain) error { + info, err := domain.GetInfo() if err != nil { return virerr.ErrorGen(virerr.DomainStatusError, err) } @@ -24,14 +23,14 @@ func (DI *DomainInfo) GetInfo(domain *domCon.Domain) error { return nil } -func (DP *DomainState) GetInfo(domain *domCon.Domain) error { - info, _, err := domain.Domain.GetState() +func (DP *DomainState) GetInfo(domain Domain) error { + info, _, err := domain.GetState() //searching for coresponding second parameter, "Reason" if err != nil { return virerr.ErrorGen(virerr.DomainStatusError, err) } - uuidBytes, err := domain.Domain.GetUUID() + uuidBytes, err := domain.GetUUID() if err != nil { return virerr.ErrorGen(virerr.InvalidUUID, err) } @@ -42,7 +41,7 @@ func (DP *DomainState) GetInfo(domain *domCon.Domain) error { DP.DomainState = info DP.UUID = string(uuidParsed.String()) - userInfo, err := domain.Domain.GetGuestInfo(libvirt.DOMAIN_GUEST_INFO_USERS, 0) + userInfo, err := domain.GetGuestInfo(libvirt.DOMAIN_GUEST_INFO_USERS, 0) if err != nil { return virerr.ErrorGen(virerr.DomainStatusError, fmt.Errorf("error retreving guest info: %w", err)) } @@ -50,7 +49,7 @@ func (DP *DomainState) GetInfo(domain *domCon.Domain) error { return nil } -func DomainDetailFactory(Handler DataTypeHandler, dom *domCon.Domain) *DomainDetail { +func DomainDetailFactory(Handler DataTypeHandler, dom Domain) *DomainDetail { return &DomainDetail{ DataHandle: Handler, Domain: dom, diff --git a/vm/service/status/instStatus.go b/vm/service/status/instStatus.go index ddccba4..2a055f0 100644 --- a/vm/service/status/instStatus.go +++ b/vm/service/status/instStatus.go @@ -4,10 +4,9 @@ import ( "fmt" virerr "github.com/easy-cloud-Knet/KWS_Core/error" - "libvirt.org/go/libvirt" ) -func (AII *AllInstInfo) GetAllinstInfo(LibvirtInst *libvirt.Connect) error { +func (AII *AllInstInfo) GetAllinstInfo(LibvirtInst Connect) error { domains, err := LibvirtInst.ListAllDomains(0) //alldomain if err != nil { @@ -41,7 +40,7 @@ func InstDataTypeRouter(types InstDataType) (InstDataTypeHandler, error) { return nil, virerr.ErrorGen(virerr.InvalidParameter, fmt.Errorf("unsupported type")) } -func InstDetailFactory(handler InstDataTypeHandler, LibvirtInst *libvirt.Connect) (*InstDetail, error) { +func InstDetailFactory(handler InstDataTypeHandler, LibvirtInst Connect) (*InstDetail, error) { if err := handler.GetAllinstInfo(LibvirtInst); err != nil { return nil, err } diff --git a/vm/service/status/status_test.go b/vm/service/status/status_test.go new file mode 100644 index 0000000..a899e41 --- /dev/null +++ b/vm/service/status/status_test.go @@ -0,0 +1,159 @@ +package status + +import ( + "errors" + "fmt" + "testing" + + virerr "github.com/easy-cloud-Knet/KWS_Core/error" + "libvirt.org/go/libvirt" +) + +// mockDomain implements Domain interface +type mockDomain struct { + infoResult *libvirt.DomainInfo + infoErr error + stateResult libvirt.DomainState + stateErr error + uuidResult []byte + uuidErr error + guestInfoResult *libvirt.DomainGuestInfo + guestInfoErr error +} + +func (m *mockDomain) GetInfo() (*libvirt.DomainInfo, error) { + return m.infoResult, m.infoErr +} +func (m *mockDomain) GetState() (libvirt.DomainState, int, error) { + return m.stateResult, 0, m.stateErr +} +func (m *mockDomain) GetUUID() ([]byte, error) { + return m.uuidResult, m.uuidErr +} +func (m *mockDomain) GetGuestInfo(types libvirt.DomainGuestInfoTypes, flags uint32) (*libvirt.DomainGuestInfo, error) { + return m.guestInfoResult, m.guestInfoErr +} + +// mockConnect implements Connect interface +type mockConnect struct { + domains []libvirt.Domain + err error +} + +func (m *mockConnect) ListAllDomains(flags libvirt.ConnectListAllDomainsFlags) ([]libvirt.Domain, error) { + return m.domains, m.err +} + +// valid 16-byte UUID for testing +var testUUIDBytes = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + +func TestDomainInfo_GetInfo_Success(t *testing.T) { + mock := &mockDomain{ + infoResult: &libvirt.DomainInfo{ + State: 1, + MaxMem: 2048, + Memory: 1024, + NrVirtCpu: 2, + CpuTime: 100, + }, + } + di := &DomainInfo{} + if err := di.GetInfo(mock); err != nil { + t.Fatalf("expected nil, got %v", err) + } + if di.MaxMem != 2048 || di.NrVirtCpu != 2 { + t.Errorf("fields not populated correctly: %+v", di) + } +} + +func TestDomainInfo_GetInfo_Error(t *testing.T) { + mock := &mockDomain{infoErr: fmt.Errorf("libvirt error")} + err := (&DomainInfo{}).GetInfo(mock) + if err == nil { + t.Fatal("expected error, got nil") + } + if !errors.Is(err, virerr.DomainStatusError) { + t.Errorf("expected DomainStatusError, got %v", err) + } +} + +func TestDomainState_GetInfo_Success(t *testing.T) { + mock := &mockDomain{ + stateResult: libvirt.DomainState(1), + uuidResult: testUUIDBytes, + guestInfoResult: &libvirt.DomainGuestInfo{}, + } + ds := &DomainState{} + if err := ds.GetInfo(mock); err != nil { + t.Fatalf("expected nil, got %v", err) + } + if ds.UUID == "" { + t.Error("UUID not populated") + } +} + +func TestDomainState_GetInfo_StateError(t *testing.T) { + mock := &mockDomain{stateErr: fmt.Errorf("state error")} + err := (&DomainState{}).GetInfo(mock) + if !errors.Is(err, virerr.DomainStatusError) { + t.Errorf("expected DomainStatusError, got %v", err) + } +} + +func TestDomainState_GetInfo_UUIDError(t *testing.T) { + mock := &mockDomain{ + stateResult: libvirt.DomainState(1), + uuidErr: fmt.Errorf("uuid error"), + } + err := (&DomainState{}).GetInfo(mock) + if !errors.Is(err, virerr.InvalidUUID) { + t.Errorf("expected InvalidUUID, got %v", err) + } +} + +func TestDomainState_GetInfo_GuestInfoError(t *testing.T) { + mock := &mockDomain{ + stateResult: libvirt.DomainState(1), + uuidResult: testUUIDBytes, + guestInfoErr: fmt.Errorf("guest info error"), + } + err := (&DomainState{}).GetInfo(mock) + if !errors.Is(err, virerr.DomainStatusError) { + t.Errorf("expected DomainStatusError, got %v", err) + } +} + +func TestAllInstInfo_GetAllinstInfo_ListError(t *testing.T) { + mock := &mockConnect{err: fmt.Errorf("libvirt error")} + err := (&AllInstInfo{}).GetAllinstInfo(mock) + if !errors.Is(err, virerr.HostStatusError) { + t.Errorf("expected HostStatusError, got %v", err) + } +} + +func TestAllInstInfo_GetAllinstInfo_EmptyList(t *testing.T) { + mock := &mockConnect{domains: []libvirt.Domain{}} + aii := &AllInstInfo{} + if err := aii.GetAllinstInfo(mock); err != nil { + t.Fatalf("expected nil, got %v", err) + } + if aii.Totalmaxmem != 0 || aii.TotalVCpu != 0 { + t.Errorf("expected zeros, got %+v", aii) + } +} + +func TestDataTypeRouter_ValidTypes(t *testing.T) { + cases := []DomainDataType{DomState, BasicInfo, GuestInfoUser, GuestInfoOS, GuestInfoFS, GuestInfoDisk} + for _, c := range cases { + if _, err := DataTypeRouter(c); err != nil { + t.Errorf("DataTypeRouter(%d) returned error: %v", c, err) + } + } +} + +func TestDataTypeRouter_InvalidType(t *testing.T) { + _, err := DataTypeRouter(DomainDataType(99)) + if !errors.Is(err, virerr.InvalidParameter) { + t.Errorf("expected InvalidParameter, got %v", err) + } +}