Skip to main content
Glama
test_virtualization_live.py9.09 kB
""" Live integration tests for TrueNAS virtualization tools These tests run against actual TrueNAS servers and require: - TRUENAS_URL and TRUENAS_API_KEY environment variables set - Test resources created manually or by this test Test resources use the 'mcp-test-' prefix to avoid conflicts with production. """ import asyncio import os import pytest from typing import Optional # Skip all tests if not configured pytestmark = pytest.mark.skipif( not os.environ.get("TRUENAS_URL"), reason="TRUENAS_URL not set - skipping live tests" ) class TestAppToolsLive: """Live tests for AppTools""" @pytest.fixture def app_tools(self): from truenas_mcp_server.tools.apps import AppTools return AppTools() @pytest.mark.asyncio async def test_list_apps(self, app_tools): """Test listing all apps (read-only, safe)""" result = await app_tools.list_apps() assert result["success"] is True assert "apps" in result assert "metadata" in result print(f"\nFound {result['metadata']['total_apps']} apps") for app in result["apps"]: print(f" - {app['name']}: {app['state']}") @pytest.mark.asyncio async def test_get_app_existing(self, app_tools): """Test getting an existing app""" # First list apps to find one list_result = await app_tools.list_apps() if not list_result["apps"]: pytest.skip("No apps found to test") app_name = list_result["apps"][0]["name"] result = await app_tools.get_app(app_name) assert result["success"] is True assert result["app"]["name"] == app_name @pytest.mark.asyncio async def test_get_app_config_existing(self, app_tools): """Test getting app config (uses quirky plain string body!)""" list_result = await app_tools.list_apps() if not list_result["apps"]: pytest.skip("No apps found to test") app_name = list_result["apps"][0]["name"] result = await app_tools.get_app_config(app_name) assert result["success"] is True assert result["app_name"] == app_name assert "config" in result print(f"\nApp {app_name} config keys: {list(result['config'].keys()) if result['config'] else 'empty'}") @pytest.mark.asyncio async def test_get_app_nonexistent(self, app_tools): """Test getting a non-existent app""" result = await app_tools.get_app("nonexistent-app-xyz123") assert result["success"] is False assert "not found" in result["error"].lower() class TestInstanceToolsLive: """Live tests for InstanceTools""" @pytest.fixture def instance_tools(self): from truenas_mcp_server.tools.instances import InstanceTools return InstanceTools() @pytest.mark.asyncio async def test_list_instances(self, instance_tools): """Test listing all Incus instances (read-only, safe)""" result = await instance_tools.list_instances() assert result["success"] is True assert "instances" in result assert "metadata" in result print(f"\nFound {result['metadata']['total_instances']} instances") for inst in result["instances"]: print(f" - {inst['name']} ({inst['type']}): {inst['status']} - {inst['cpu']} CPU, {inst['memory_gb']}GB RAM") @pytest.mark.asyncio async def test_list_instances_filter_vm(self, instance_tools): """Test filtering instances by type""" result = await instance_tools.list_instances(instance_type="VM") assert result["success"] is True for inst in result["instances"]: assert inst["type"] == "VM" @pytest.mark.asyncio async def test_list_instances_filter_container(self, instance_tools): """Test filtering instances by type""" result = await instance_tools.list_instances(instance_type="CONTAINER") assert result["success"] is True for inst in result["instances"]: assert inst["type"] == "CONTAINER" @pytest.mark.asyncio async def test_get_instance_existing(self, instance_tools): """Test getting an existing instance""" list_result = await instance_tools.list_instances() if not list_result["instances"]: pytest.skip("No instances found to test") inst_name = list_result["instances"][0]["name"] result = await instance_tools.get_instance(inst_name) assert result["success"] is True assert result["instance"]["name"] == inst_name @pytest.mark.asyncio async def test_get_instance_nonexistent(self, instance_tools): """Test getting a non-existent instance""" result = await instance_tools.get_instance("nonexistent-instance-xyz123") assert result["success"] is False assert "not found" in result["error"].lower() @pytest.mark.asyncio async def test_list_instance_devices(self, instance_tools): """Test listing devices for an instance""" list_result = await instance_tools.list_instances() if not list_result["instances"]: pytest.skip("No instances found to test") inst_name = list_result["instances"][0]["name"] result = await instance_tools.list_instance_devices(inst_name) assert result["success"] is True assert "devices" in result print(f"\nInstance {inst_name} has {result['metadata']['device_count']} devices") class TestLegacyVMToolsLive: """Live tests for LegacyVMTools""" @pytest.fixture def vm_tools(self): from truenas_mcp_server.tools.vms import LegacyVMTools return LegacyVMTools() @pytest.mark.asyncio async def test_list_legacy_vms(self, vm_tools): """Test listing all legacy VMs (read-only, safe)""" result = await vm_tools.list_legacy_vms() assert result["success"] is True assert "vms" in result assert "metadata" in result print(f"\nFound {result['metadata']['total_vms']} legacy VMs") for vm in result["vms"]: print(f" - {vm['name']} (ID: {vm['id']}): {vm['status']} - {vm['vcpus']} vCPU, {vm['memory_mb']}MB RAM") @pytest.mark.asyncio async def test_get_legacy_vm_existing(self, vm_tools): """Test getting an existing legacy VM""" list_result = await vm_tools.list_legacy_vms() if not list_result["vms"]: pytest.skip("No legacy VMs found to test") vm_id = list_result["vms"][0]["id"] result = await vm_tools.get_legacy_vm(vm_id) assert result["success"] is True assert result["vm"]["id"] == vm_id @pytest.mark.asyncio async def test_get_legacy_vm_nonexistent(self, vm_tools): """Test getting a non-existent legacy VM""" result = await vm_tools.get_legacy_vm(99999) assert result["success"] is False assert "not found" in result["error"].lower() class TestIntegration: """Integration tests that exercise multiple tools together""" @pytest.mark.asyncio async def test_full_workflow(self): """ Test a full workflow: 1. List resources 2. Get details of each type 3. Verify API quirks are handled correctly """ from truenas_mcp_server.tools.apps import AppTools from truenas_mcp_server.tools.instances import InstanceTools from truenas_mcp_server.tools.vms import LegacyVMTools app_tools = AppTools() instance_tools = InstanceTools() vm_tools = LegacyVMTools() # List all resource types apps = await app_tools.list_apps() instances = await instance_tools.list_instances() vms = await vm_tools.list_legacy_vms() print("\n=== TrueNAS Virtualization Summary ===") print(f"Apps: {apps['metadata']['total_apps']}") print(f"Incus Instances: {instances['metadata']['total_instances']}") print(f"Legacy VMs: {vms['metadata']['total_vms']}") # Verify all succeeded assert apps["success"] assert instances["success"] assert vms["success"] if __name__ == "__main__": # Run quick smoke test async def smoke_test(): from truenas_mcp_server.tools.apps import AppTools from truenas_mcp_server.tools.instances import InstanceTools from truenas_mcp_server.tools.vms import LegacyVMTools print("Testing AppTools...") app_tools = AppTools() apps = await app_tools.list_apps() print(f" Found {apps['metadata']['total_apps']} apps") print("Testing InstanceTools...") instance_tools = InstanceTools() instances = await instance_tools.list_instances() print(f" Found {instances['metadata']['total_instances']} instances") print("Testing LegacyVMTools...") vm_tools = LegacyVMTools() vms = await vm_tools.list_legacy_vms() print(f" Found {vms['metadata']['total_vms']} legacy VMs") print("\nAll smoke tests passed!") asyncio.run(smoke_test())

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vespo92/TrueNasCoreMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server