Skip to content

Testing Strategy

This document outlines a recommended testing strategy for the Palo Alto Networks MCP Server.

Unit Tests

Unit tests focus on testing individual functions and classes in isolation.

Testing the PAN-OS API Client

The PanOSAPIClient class should be tested with mocked HTTP responses to avoid making actual API calls during testing.

import pytest
import xml.etree.ElementTree as ET
from unittest.mock import AsyncMock, patch

from palo_alto_mcp.config import Settings
from palo_alto_mcp.pan_os_api import PanOSAPIClient

@pytest.mark.asyncio
async def test_get_address_objects():
    # Create mock settings
    settings = Settings(
        panos_hostname="firewall.example.com",
        panos_api_key="mock-api-key"
    )

    # Create mock XML response
    xml_response = """
    <response status="success">
        <result>
            <address>
                <entry name="test-address">
                    <ip-netmask>192.168.1.1/32</ip-netmask>
                    <description>Test address</description>
                </entry>
            </address>
        </result>
    </response>
    """

    # Mock the HTTP client
    with patch("httpx.AsyncClient") as mock_client:
        mock_instance = mock_client.return_value
        mock_instance.get = AsyncMock()
        mock_instance.get.return_value.text = xml_response
        mock_instance.get.return_value.raise_for_status = AsyncMock()

        # Create client and call method
        async with PanOSAPIClient(settings) as client:
            address_objects = await client.get_address_objects()

        # Assert results
        assert len(address_objects) == 1
        assert address_objects[0]["name"] == "test-address"
        assert address_objects[0]["type"] == "ip-netmask"
        assert address_objects[0]["value"] == "192.168.1.1/32"
        assert address_objects[0]["description"] == "Test address"

Testing the Server Tools

The server tools should be tested with a mocked PanOSAPIClient.

import pytest
from unittest.mock import AsyncMock, patch

from palo_alto_mcp.server import retrieve_address_objects

@pytest.mark.asyncio
async def test_retrieve_address_objects():
    # Mock the PanOSAPIClient
    with patch("palo_alto_mcp.server.PanOSAPIClient") as mock_client_class:
        mock_client = AsyncMock()
        mock_client_class.return_value.__aenter__.return_value = mock_client

        # Mock the get_address_objects method
        mock_client.get_address_objects.return_value = [
            {
                "name": "test-address",
                "type": "ip-netmask",
                "value": "192.168.1.1/32",
                "description": "Test address"
            }
        ]

        # Call the tool function
        result = await retrieve_address_objects(None)

        # Assert the result contains the expected information
        assert "test-address" in result
        assert "192.168.1.1/32" in result
        assert "Test address" in result

Integration Tests

Integration tests focus on testing the interaction between different components of the system.

Testing the MCP Server

The MCP server can be tested using the SDK's create_connected_server_and_client_session function.

import pytest
from mcp.server.testing import create_connected_server_and_client_session
from mcp.client import Client

from palo_alto_mcp.server import mcp

@pytest.mark.asyncio
async def test_mcp_server():
    # Create a connected server and client session
    async with create_connected_server_and_client_session(mcp) as client:
        # List available tools
        tools = await client.list_tools()

        # Assert that the expected tools are available
        tool_names = [tool.name for tool in tools]
        assert "show_system_info" in tool_names
        assert "retrieve_address_objects" in tool_names
        assert "retrieve_security_zones" in tool_names
        assert "retrieve_security_policies" in tool_names

End-to-End (E2E) Tests

End-to-end tests focus on testing complete workflows, potentially involving real Palo Alto Networks firewalls.

Warning

E2E tests should be run in a controlled environment with a dedicated test firewall to avoid impacting production systems.

Testing with a Real Firewall

import pytest
import os
from mcp.server.testing import create_connected_server_and_client_session
from mcp.client import Client

from palo_alto_mcp.server import mcp

@pytest.mark.e2e
@pytest.mark.skipif(not os.environ.get("E2E_TEST"), reason="E2E tests disabled")
@pytest.mark.asyncio
async def test_e2e_retrieve_address_objects():
    # Create a connected server and client session
    async with create_connected_server_and_client_session(mcp) as client:
        # Call the retrieve_address_objects tool
        result = await client.call_tool("retrieve_address_objects")

        # Assert that the result is not empty
        assert result.content
        assert "# Palo Alto Networks Firewall Address Objects" in result.content

Testing Tools and Frameworks

  • pytest: The primary testing framework
  • pytest-asyncio: For testing asynchronous code
  • unittest.mock: For mocking dependencies
  • httpx: For making HTTP requests in tests
  • mcp.server.testing: For testing MCP servers

Continuous Integration (CI)

Tests should be incorporated into a CI pipeline (e.g., GitHub Actions, GitLab CI) to ensure that they are run automatically on every commit.

Example GitHub Actions Workflow

name: Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.10'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -e ".[dev]"
    - name: Run tests
      run: |
        pytest

Test Coverage

Test coverage should be monitored to ensure that all parts of the codebase are adequately tested.

pytest --cov=palo_alto_mcp

Mocking Strategies

Mocking HTTP Responses

HTTP responses can be mocked using unittest.mock to patch the httpx.AsyncClient class.

Mocking the Palo Alto Networks XML API

The Palo Alto Networks XML API can be mocked by providing pre-defined XML responses for different API calls.

Mocking MCP Clients

MCP clients can be mocked using the SDK's testing utilities.