import os
import sys
from http import HTTPStatus
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SRC_ROOT = os.path.join(PROJECT_ROOT, 'src')
if SRC_ROOT not in sys.path:
sys.path.insert(0, SRC_ROOT)
import json
import pytest
from unittest.mock import patch, MagicMock
from virtcca_deploy.services.db_service import db, ComputeNode, VmInstance
from virtcca_deploy.services.vm_service import VmService, init_vm_service
from virtcca_deploy.services.task_service import init_task_service
import virtcca_deploy.common.constants as constants
class TestVmServiceQuery:
def test_query_vm_states_by_nodes(self, app):
"""测试根据节点查询虚拟机状态"""
with app.app_context():
init_task_service()
mock_vlan_pool_manager = MagicMock()
vm_service = VmService(None, mock_vlan_pool_manager)
node = ComputeNode(
nodename="compute01",
ip="192.168.1.100",
physical_cpu=8,
memory=16384,
memory_free=8192,
secure_memory=4096,
secure_memory_free=4096,
secure_numa_topology="{}"
)
db.session.add(node)
vm1 = VmInstance(
vm_id="compute01-1",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([
{
"node_name": "compute01",
"mac_address": "00:11:22:33:44:55",
"vlan_id": 100,
"ip_address": "192.168.1.10",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
},
{
"node_name":
"compute01",
"mac_address":
"00:11:22:33:44:56",
"vlan_id": 200,
"ip_address": "192.168.1.11",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}
])
)
vm2 = VmInstance(
vm_id="compute01-2",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([
{
"node_name": "compute01",
"mac_address": "00:11:22:33:44:57",
"vlan_id": 100,
"ip_address": "192.168.1.12",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}
])
)
db.session.add_all([vm1, vm2])
db.session.commit()
with patch('virtcca_deploy.services.vm_service.NetworkService') as mock_network_service, \
patch('virtcca_deploy.services.node_service.NodeService') as mock_node_service:
mock_node_service.get_nodes_by_ip_list.return_value = ([node], None)
mock_network_instance = MagicMock()
mock_response = MagicMock()
mock_response.status_code = HTTPStatus.OK
mock_response.json.return_value = {
"data": {
"compute01-1": "RUNNING",
"compute01-2": "SHUTOFF"
},
"message": ""
}
mock_network_instance.query_cvm_state.return_value = mock_response
mock_network_service.return_value = mock_network_instance
result, message = vm_service.query_vm_states(nodes=["compute01"], page=1, page_size=10)
assert result is not None
assert "vm_info" in result
assert "pagination" in result
vm_info = result["vm_info"]
assert len(vm_info) == 2
assert "compute01-1" in vm_info
assert "compute01-2" in vm_info
assert vm_info["compute01-1"]["state"] == "RUNNING"
assert vm_info["compute01-2"]["state"] == "SHUTOFF"
pagination = result["pagination"]
assert pagination["page"] == 1
assert pagination["page_size"] == 10
assert pagination["entry_num"] == 2
def test_query_vm_states_by_vm_ids(self, app):
"""测试根据虚拟机ID查询虚拟机状态"""
with app.app_context():
init_task_service()
mock_vlan_pool_manager = MagicMock()
vm_service = VmService(None, mock_vlan_pool_manager)
node = ComputeNode(
nodename="compute01",
ip="192.168.1.100",
physical_cpu=8,
memory=16384,
memory_free=8192,
secure_memory=4096,
secure_memory_free=4096,
secure_numa_topology="{}"
)
db.session.add(node)
vm1 = VmInstance(
vm_id="compute01-1",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([
{
"node_name": "compute01",
"mac_address": "00:11:22:33:44:55",
"vlan_id": 100,
"ip_address": "192.168.1.10",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}
])
)
vm2 = VmInstance(
vm_id="compute01-2",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([
{
"node_name": "compute01",
"mac_address": "00:11:22:33:44:56",
"vlan_id": 100,
"ip_address": "192.168.1.11",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}
])
)
db.session.add_all([vm1, vm2])
db.session.commit()
with patch('virtcca_deploy.services.vm_service.NetworkService') as mock_network_service, \
patch('virtcca_deploy.services.node_service.NodeService') as mock_node_service:
mock_node_service.get_nodes_by_ip_list.return_value = ([node], None)
mock_network_instance = MagicMock()
mock_response = MagicMock()
mock_response.status_code = HTTPStatus.OK
mock_response.json.return_value = {
"data": {
"compute01-1": "RUNNING",
"compute01-2": "SHUTOFF"
},
"message": ""
}
mock_network_instance.query_cvm_state.return_value = mock_response
mock_network_service.return_value = mock_network_instance
result, message = vm_service.query_vm_states(vm_ids=["compute01-1"], page=1, page_size=10)
assert result is not None
assert "vm_info" in result
assert "pagination" in result
vm_info = result["vm_info"]
assert len(vm_info) == 1
assert "compute01-1" in vm_info
assert "compute01-2" not in vm_info
assert vm_info["compute01-1"]["state"] == "RUNNING"
def test_query_vm_states_pagination(self, app):
"""测试分页查询"""
with app.app_context():
init_task_service()
mock_vlan_pool_manager = MagicMock()
vm_service = VmService(None, mock_vlan_pool_manager)
node = ComputeNode(
nodename="compute01",
ip="192.168.1.100",
physical_cpu=8,
memory=16384,
memory_free=8192,
secure_memory=4096,
secure_memory_free=4096,
secure_numa_topology="{}"
)
db.session.add(node)
vms = []
for i in range(15):
vm = VmInstance(
vm_id=f"compute01-{i+1}",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([
{
"node_name": "compute01",
"mac_address": f"00:11:22:33:44:{i:02X}",
"vlan_id": 100,
"ip_address": f"192.168.1.{i+10}",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}
])
)
vms.append(vm)
db.session.add_all(vms)
db.session.commit()
with patch('virtcca_deploy.services.vm_service.NetworkService') as mock_network_service, \
patch('virtcca_deploy.services.node_service.NodeService') as mock_node_service:
mock_node_service.get_nodes_by_ip_list.return_value = ([node], None)
mock_network_instance = MagicMock()
mock_response = MagicMock()
mock_response.status_code = HTTPStatus.OK
vm_states = {}
for i in range(15):
vm_states[f"compute01-{i+1}"] = "RUNNING" if i % 2 == 0 else "SHUTOFF"
mock_response.json.return_value = {
"data": vm_states,
"message": ""
}
mock_network_instance.query_cvm_state.return_value = mock_response
mock_network_service.return_value = mock_network_instance
result, message = vm_service.query_vm_states(nodes=["compute01"], page=1, page_size=10)
vm_info = result["vm_info"]
pagination = result["pagination"]
assert len(vm_info) == 10
assert pagination["page"] == 1
assert pagination["page_size"] == 10
assert pagination["entry_num"] == 15
result, message = vm_service.query_vm_states(nodes=["compute01"], page=2, page_size=10)
vm_info = result["vm_info"]
pagination = result["pagination"]
assert len(vm_info) == 5
assert pagination["page"] == 2
assert pagination["page_size"] == 10
assert pagination["entry_num"] == 15
def test_query_vm_states_network_failure(self, app):
"""测试网络请求失败的情况"""
with app.app_context():
init_task_service()
mock_vlan_pool_manager = MagicMock()
vm_service = VmService(None, mock_vlan_pool_manager)
node = ComputeNode(
nodename="compute01",
ip="192.168.1.100",
physical_cpu=8,
memory=16384,
memory_free=8192,
secure_memory=4096,
secure_memory_free=4096,
secure_numa_topology="{}"
)
db.session.add(node)
vm = VmInstance(
vm_id="compute01-1",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([
{
"node_name": "compute01",
"mac_address": "00:11:22:33:44:55",
"vlan_id": 100,
"ip_address": "192.168.1.10",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}
])
)
db.session.add(vm)
db.session.commit()
with patch('virtcca_deploy.services.vm_service.NetworkService') as mock_network_service, \
patch('virtcca_deploy.services.node_service.NodeService') as mock_node_service:
mock_node_service.get_nodes_by_ip_list.return_value = ([node], None)
mock_network_instance = MagicMock()
mock_response = MagicMock()
mock_response.status_code = HTTPStatus.INTERNAL_SERVER_ERROR
mock_network_instance.query_cvm_state.return_value = mock_response
mock_network_service.return_value = mock_network_instance
result, message = vm_service.query_vm_states(nodes=["compute01"])
assert result is not None
assert "vm_info" in result
vm_info = result["vm_info"]
assert "compute01-1" in vm_info
assert vm_info["compute01-1"]["state"] == "UNKNOWN"
def test_query_vm_states_node_not_found(self, app):
"""测试节点不存在的情况"""
with app.app_context():
init_task_service()
mock_vlan_pool_manager = MagicMock()
vm_service = VmService(None, mock_vlan_pool_manager)
node = ComputeNode(
nodename="compute01",
ip="192.168.1.100",
physical_cpu=8,
memory=16384,
memory_free=8192,
secure_memory=4096,
secure_memory_free=4096,
secure_numa_topology="{}"
)
db.session.add(node)
vm = VmInstance(
vm_id="compute01-1",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([
{
"node_name": "compute01",
"mac_address": "00:11:22:33:44:55",
"vlan_id": 100,
"ip_address": "192.168.1.10",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}
])
)
db.session.add(vm)
db.session.commit()
with patch('virtcca_deploy.services.vm_service.NetworkService') as mock_network_service, \
patch('virtcca_deploy.services.node_service.NodeService') as mock_node_service:
mock_node_service.get_nodes_by_ip_list.return_value = ([], None)
result, message = vm_service.query_vm_states(nodes=["compute01"])
assert result is not None
assert "vm_info" in result
vm_info = result["vm_info"]
assert "compute01-1" in vm_info
assert vm_info["compute01-1"]["state"] == "UNKNOWN"
def test_query_vm_states_invalid_json_response(self, app):
"""测试无效的JSON响应"""
with app.app_context():
init_task_service()
mock_vlan_pool_manager = MagicMock()
vm_service = VmService(None, mock_vlan_pool_manager)
node = ComputeNode(
nodename="compute01",
ip="192.168.1.100",
physical_cpu=8,
memory=16384,
memory_free=8192,
secure_memory=4096,
secure_memory_free=4096,
secure_numa_topology="{}"
)
db.session.add(node)
vm = VmInstance(
vm_id="compute01-1",
host_ip=node.ip,
host_name=node.nodename,
vm_spec_uuid="spec-123",
iface_list=json.dumps([{
"node_name": "compute01",
"mac_address": "00:11:22:33:44:55",
"vlan_id": 100,
"ip_address": "192.168.1.10",
"subnet_mask": "255.255.255.0",
"gateway": "192.168.1.1"
}])
)
db.session.add(vm)
db.session.commit()
with patch('virtcca_deploy.services.vm_service.NetworkService') as mock_network_service, \
patch('virtcca_deploy.services.node_service.NodeService') as mock_node_service:
mock_node_service.get_nodes_by_ip_list.return_value = ([node], None)
mock_network_instance = MagicMock()
mock_response = MagicMock()
mock_response.status_code = HTTPStatus.OK
mock_response.json.side_effect = json.JSONDecodeError("Invalid JSON", "", 0)
mock_network_instance.query_cvm_state.return_value = mock_response
mock_network_service.return_value = mock_network_instance
result, message = vm_service.query_vm_states(nodes=["compute01"])
assert result is not None
assert "vm_info" in result
vm_info = result["vm_info"]
assert "compute01-1" in vm_info
assert vm_info["compute01-1"]["state"] == "UNKNOWN"
def test_query_vm_states_no_vms_found(self, app):
"""测试没有虚拟机的情况"""
with app.app_context():
init_task_service()
mock_vlan_pool_manager = MagicMock()
vm_service = VmService(None, mock_vlan_pool_manager)
result, message = vm_service.query_vm_states(nodes=["compute01"])
assert result is not None
assert "vm_info" in result
assert "pagination" in result
vm_info = result["vm_info"]
pagination = result["pagination"]
assert len(vm_info) == 0
assert pagination["entry_num"] == 0