We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kpeacocke/souschef'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""
Performance tests for SousChef parsers and converters.
Tests measure execution time, memory usage, and establish baselines
for regression detection on critical parsing and conversion functions.
Uses pytest-benchmark for timing regression detection and tracks
memory consumption for large inventory processing tasks.
"""
import pytest
import yaml
from souschef.core.ansible_versions import calculate_upgrade_path
from souschef.parsers.ansible_inventory import (
parse_ansible_cfg,
parse_inventory_ini,
parse_inventory_yaml,
parse_requirements_yml,
)
@pytest.fixture
def large_ini_inventory(tmp_path):
"""
Generate a large INI inventory with 1000+ hosts.
Creates a realistic multi-group inventory for performance testing.
"""
inventory_content = "[webservers]\n"
for i in range(500):
inventory_content += (
f"web_{i:04d} ansible_host=192.168.1.{i % 255}\n" # NOSONAR - test fixture
)
inventory_content += "\n[databases]\n"
for i in range(300):
inventory_content += (
f"db_{i:04d} ansible_host=10.0.0.{i % 255}\n" # NOSONAR - test fixture
)
inventory_content += "\n[monitoring]\n"
for i in range(200):
inventory_content += (
f"mon_{i:04d} ansible_host=172.16.0.{i % 255}\n" # NOSONAR - test fixture
)
inventory_file = tmp_path / "inventory.ini"
inventory_file.write_text(inventory_content)
return str(inventory_file)
@pytest.fixture
def large_yaml_inventory(tmp_path):
"""
Generate a large YAML inventory with 1000+ hosts and variables.
Creates realistic host variables for performance testing.
"""
inventory_data = {
"all": {
"children": {
"webservers": {
"hosts": {
f"web_{i:04d}": {
"ansible_host": f"192.168.1.{i % 255}", # NOSONAR - test fixture
"http_port": 8080 + (i % 100),
"max_clients": 200 + (i % 100),
"region": ["us-east", "us-west", "eu-west"][i % 3],
"tags": ["web", "frontend", "public"],
}
for i in range(500)
}
},
"databases": {
"hosts": {
f"db_{i:04d}": {
"ansible_host": f"10.0.0.{i % 255}", # NOSONAR - test fixture
"db_port": 5432,
"max_connections": 100 + (i % 50),
"backup_enabled": i % 2 == 0,
"region": ["us-east", "us-west"][i % 2],
"tags": ["database", "backend", "private"],
}
for i in range(300)
}
},
"monitoring": {
"hosts": {
f"mon_{i:04d}": {
"ansible_host": f"172.16.0.{i % 255}", # NOSONAR - test fixture
"monitoring_port": 9090,
"scrape_interval": 15 + (i % 30),
"tags": ["monitoring", "observability"],
}
for i in range(200)
}
},
}
}
}
inventory_file = tmp_path / "inventory.yml"
with inventory_file.open("w") as f:
yaml.dump(inventory_data, f)
return str(inventory_file)
@pytest.fixture
def large_requirements_yml(tmp_path):
"""
Generate a requirements.yml with 500+ collections.
Simulates dependency inventory for performance testing.
"""
collections = [
{
"name": f"community.collection_{i:04d}",
"version": f"{1 + (i % 5)}.{i % 20}.0",
}
for i in range(500)
]
requirements_data = {"collections": collections}
requirements_file = tmp_path / "requirements.yml"
with requirements_file.open("w") as f:
yaml.dump(requirements_data, f)
return str(requirements_file)
class TestInventoryParserPerformance:
"""Benchmark tests for inventory parsing with large datasets."""
def test_parse_large_ini_inventory_benchmark(self, benchmark, large_ini_inventory):
"""
Benchmark INI inventory parser on 1000+ hosts.
Performance baseline: Should parse 1000 hosts efficiently.
Creates performance baseline for regression detection.
"""
def parse_ini():
return parse_inventory_ini(large_ini_inventory)
result = benchmark(parse_ini)
assert isinstance(result, dict)
assert "groups" in result or "hosts" in result
# INI parser returns {groups: {...}, hosts: {...}}
if "hosts" in result:
assert len(result["hosts"]) > 0
def test_parse_large_yaml_inventory_benchmark(
self, benchmark, large_yaml_inventory
):
"""
Benchmark YAML inventory parser on 1000+ hosts with variables.
Performance baseline: Should parse 1000 hosts with vars efficiently.
Creates baseline for regression detection.
"""
def parse_yaml():
return parse_inventory_yaml(large_yaml_inventory)
result = benchmark(parse_yaml)
assert isinstance(result, dict)
# YAML parser returns nested structure
assert "all" in result or "webservers" in result or "databases" in result
def test_parse_yaml_inventory_variable_overhead(
self, benchmark, large_yaml_inventory
):
"""
Measure overhead of parsing host variables.
Tracks whether variable processing impacts parsing performance.
"""
def parse_with_vars():
result = parse_inventory_yaml(large_yaml_inventory)
# Verify variables were extracted
return result
benchmark(parse_with_vars)
class TestRequirementsParserPerformance:
"""Benchmark tests for requirements.yml parsing with large collections."""
def test_parse_large_requirements_benchmark(
self, benchmark, large_requirements_yml
):
"""
Benchmark requirements.yml parser on 500+ collections.
Performance baseline: Creates baseline for regression detection.
"""
def parse_requirements():
return parse_requirements_yml(large_requirements_yml)
result = benchmark(parse_requirements)
assert isinstance(result, dict)
assert len(result) >= 500
# Verify collection name format
assert any("community.collection" in key for key in result)
class TestUpgradePathPerformance:
"""Benchmark tests for upgrade path calculation."""
@pytest.mark.parametrize(
"from_ver,to_ver",
[
("2.9", "2.17"),
("2.10", "2.15"),
("2.11", "2.17"),
],
)
def test_calculate_upgrade_path_benchmark(self, benchmark, from_ver, to_ver):
"""
Benchmark upgrade path calculation across versions.
Performance baseline: Should calculate paths in < 10ms.
Regression detection: Alerts if calculation time increases > 30%.
"""
def calc_path():
return calculate_upgrade_path(from_ver, to_ver)
result = benchmark(calc_path)
assert isinstance(result, dict)
# Verify result structure
assert (
"direct_upgrade" in result
or "steps" in result
or "intermediate_versions" in result
)
class TestAnsibleConfigParserPerformance:
"""Benchmark tests for ansible.cfg parsing."""
def test_parse_ansible_cfg_large_config_benchmark(self, benchmark, tmp_path):
"""
Benchmark ansible.cfg parser with large configuration files.
Performance baseline: Should parse large configs in < 50ms.
Regression detection: Alerts if parsing time increases > 20%.
"""
# Create a large ansible.cfg with many options
config_content = "[defaults]\n"
for i in range(100):
config_content += f"# Comment {i}\n"
config_content += f"option_{i} = value_{i}\n"
config_content += "\n[inventory]\n"
for i in range(50):
config_content += f"inv_option_{i} = inv_value_{i}\n"
config_file = tmp_path / "ansible.cfg"
config_file.write_text(config_content)
def parse_config():
return parse_ansible_cfg(str(config_file))
result = benchmark(parse_config)
assert isinstance(result, dict)
class TestMemoryUsageRegression:
"""Tests to detect memory usage regressions on large datasets."""
def test_large_ini_inventory_memory_stable(self, large_ini_inventory):
"""
Verify INI inventory parsing doesn't leak memory.
Parses inventory multiple times and ensures no unbounded growth.
"""
results = []
for _ in range(5):
result = parse_inventory_ini(large_ini_inventory)
# Count hosts from the hosts dict
host_count = len(result.get("hosts", {}))
results.append(host_count)
# All parsing results should have same number of hosts
assert len(set(results)) == 1
assert results[0] > 0
def test_large_yaml_inventory_memory_stable(self, large_yaml_inventory):
"""
Verify YAML inventory parsing doesn't leak memory.
Parses inventory multiple times and ensures no unbounded growth.
"""
results = []
for _ in range(5):
result = parse_inventory_yaml(large_yaml_inventory)
results.append(str(result)) # Stable representation
# All parses should produce consistent results
assert all(r == results[0] for r in results)
class TestRegressionBaselines:
"""Establish and verify performance regression baselines."""
def test_ini_parser_regression_baseline(self, tmp_path, benchmark):
"""
Establish INI parser baseline for regression detection.
Creates a standard 100-host inventory and benchmarks repeatedly
to establish a stable baseline.
"""
# Standard test inventory
inventory_content = "[servers]\n"
for i in range(100):
inventory_content += (
f"server_{i:03d} ansible_host=10.0.0.{i}\n" # NOSONAR - test fixture
)
inventory_file = tmp_path / "inventory.ini"
inventory_file.write_text(inventory_content)
def parse_standard():
return parse_inventory_ini(str(inventory_file))
# Run benchmark which will establish baseline
result = benchmark(parse_standard)
assert isinstance(result, dict)
assert "hosts" in result or "groups" in result
def test_yaml_parser_regression_baseline(self, tmp_path, benchmark):
"""
Establish YAML parser baseline for regression detection.
Creates a standard 100-host inventory with variables and benchmarks
repeatedly to establish a stable baseline.
"""
inventory_data = {
"all": {
"hosts": {
f"server_{i:03d}": {
"ansible_host": f"10.0.0.{i}", # NOSONAR - test fixture
"custom_var": f"value_{i}",
}
for i in range(100)
}
}
}
inventory_file = tmp_path / "inventory.yml"
with inventory_file.open("w") as f:
yaml.dump(inventory_data, f)
def parse_standard():
return parse_inventory_yaml(str(inventory_file))
result = benchmark(parse_standard)
assert isinstance(result, dict)
def test_upgrade_path_regression_baseline(self, benchmark):
"""
Establish upgrade path calculation baseline.
Tests common upgrade scenarios and establishes performance baseline.
"""
def calc_common_path():
return calculate_upgrade_path("2.9", "2.17")
result = benchmark(calc_common_path)
assert isinstance(result, dict)
class TestComplexScenarios:
"""Performance tests for realistic complex scenarios."""
def test_parse_inventory_with_mixed_groups_and_vars(self, benchmark, tmp_path):
"""
Benchmark parsing complex inventory with mixed groups and variables.
Simulates real-world inventory with group vars, host vars, and nested
relationships.
"""
inventory_data = {
"all": {
"vars": {"ansible_user": "deploy", "ansible_port": 22},
"children": {
"production": {
"vars": {"env": "prod", "backup_level": "full"},
"hosts": {
f"prod_server_{i:03d}": {
"ansible_host": f"10.1.0.{i}",
"role": "web" if i % 2 == 0 else "app",
}
for i in range(200)
},
},
"staging": {
"vars": {"env": "stage", "backup_level": "incremental"},
"hosts": {
f"stage_server_{i:03d}": {
"ansible_host": f"10.2.0.{i}",
"role": "web"
if i % 3 == 0
else "app"
if i % 3 == 1
else "db",
}
for i in range(150)
},
},
},
}
}
inventory_file = tmp_path / "inventory.yml"
with inventory_file.open("w") as f:
yaml.dump(inventory_data, f)
def parse_complex():
return parse_inventory_yaml(str(inventory_file))
result = benchmark(parse_complex)
assert isinstance(result, dict)
assert len(result) > 0