AgentGraph / tests /unit /test_config.py
wu981526092's picture
Add comprehensive perturbation testing system with E2E tests
795b72e
"""
Unit tests for agentgraph/testing/config.py
Tests configuration models and preset configurations.
"""
import pytest
from pydantic import ValidationError
from agentgraph.testing.config import (
ExecutionConfig,
JailbreakTestConfig,
DemographicConfig,
CounterfactualBiasTestConfig,
PerturbationTestConfig,
PRESET_CONFIGS,
EXTENDED_DEMOGRAPHICS,
get_preset_config,
create_config_from_dict,
)
class TestExecutionConfig:
"""Tests for ExecutionConfig model."""
def test_default_values(self):
"""Test default configuration values."""
config = ExecutionConfig()
assert config.max_workers == 5
assert config.max_retries == 3
assert config.base_delay == 1.0
assert config.max_delay == 60.0
assert config.rate_limit_per_minute == 60
def test_custom_values(self):
"""Test custom configuration values."""
config = ExecutionConfig(
max_workers=10,
max_retries=5,
base_delay=2.0,
max_delay=120.0,
rate_limit_per_minute=100
)
assert config.max_workers == 10
assert config.max_retries == 5
assert config.base_delay == 2.0
assert config.max_delay == 120.0
assert config.rate_limit_per_minute == 100
def test_max_workers_validation(self):
"""Test max_workers validation bounds."""
# Valid bounds
assert ExecutionConfig(max_workers=1).max_workers == 1
assert ExecutionConfig(max_workers=20).max_workers == 20
# Invalid bounds
with pytest.raises(ValidationError):
ExecutionConfig(max_workers=0)
with pytest.raises(ValidationError):
ExecutionConfig(max_workers=21)
def test_max_retries_validation(self):
"""Test max_retries validation bounds."""
assert ExecutionConfig(max_retries=1).max_retries == 1
assert ExecutionConfig(max_retries=10).max_retries == 10
with pytest.raises(ValidationError):
ExecutionConfig(max_retries=0)
with pytest.raises(ValidationError):
ExecutionConfig(max_retries=11)
def test_base_delay_validation(self):
"""Test base_delay validation bounds."""
assert ExecutionConfig(base_delay=0.1).base_delay == 0.1
assert ExecutionConfig(base_delay=10.0).base_delay == 10.0
with pytest.raises(ValidationError):
ExecutionConfig(base_delay=0.0)
with pytest.raises(ValidationError):
ExecutionConfig(base_delay=11.0)
class TestJailbreakTestConfig:
"""Tests for JailbreakTestConfig model."""
def test_default_values(self):
"""Test default configuration values."""
config = JailbreakTestConfig()
assert config.enabled is True
assert config.num_techniques == 10
assert config.technique_categories is None
assert config.random_seed is None
assert config.prompt_source == "standard"
assert config.custom_prompts is None
def test_num_techniques_validation(self):
"""Test num_techniques validation bounds."""
assert JailbreakTestConfig(num_techniques=1).num_techniques == 1
assert JailbreakTestConfig(num_techniques=50).num_techniques == 50
with pytest.raises(ValidationError):
JailbreakTestConfig(num_techniques=0)
with pytest.raises(ValidationError):
JailbreakTestConfig(num_techniques=51)
def test_technique_categories(self):
"""Test technique categories filtering."""
config = JailbreakTestConfig(
technique_categories=["DAN", "Omega"]
)
assert config.technique_categories == ["DAN", "Omega"]
def test_custom_prompts(self):
"""Test custom prompts configuration."""
custom = [
{"name": "test", "prompt": "Test prompt", "description": "Test"}
]
config = JailbreakTestConfig(custom_prompts=custom)
assert config.custom_prompts == custom
def test_disabled_config(self):
"""Test disabled jailbreak testing."""
config = JailbreakTestConfig(enabled=False)
assert config.enabled is False
class TestDemographicConfig:
"""Tests for DemographicConfig model."""
def test_basic_demographic(self):
"""Test basic demographic configuration."""
demo = DemographicConfig(gender="male", race="White")
assert demo.gender == "male"
assert demo.race == "White"
def test_str_representation(self):
"""Test string representation."""
demo = DemographicConfig(gender="female", race="Black")
assert str(demo) == "female Black"
def test_various_demographics(self):
"""Test various demographic combinations."""
demos = [
("male", "White"),
("female", "Black"),
("non-binary", "Asian"),
("male", "Hispanic"),
]
for gender, race in demos:
demo = DemographicConfig(gender=gender, race=race)
assert demo.gender == gender
assert demo.race == race
class TestCounterfactualBiasTestConfig:
"""Tests for CounterfactualBiasTestConfig model."""
def test_default_values(self):
"""Test default configuration values."""
config = CounterfactualBiasTestConfig()
assert config.enabled is True
assert len(config.demographics) == 4
assert config.include_baseline is True
assert config.comparison_mode == "both"
assert config.extended_dimensions is None
def test_comparison_mode_enum(self):
"""Test comparison mode enumeration."""
for mode in ["all_pairs", "vs_baseline", "both"]:
config = CounterfactualBiasTestConfig(comparison_mode=mode)
assert config.comparison_mode == mode
with pytest.raises(ValidationError):
CounterfactualBiasTestConfig(comparison_mode="invalid")
def test_custom_demographics(self):
"""Test custom demographics configuration."""
demos = [
DemographicConfig(gender="male", race="Asian"),
DemographicConfig(gender="female", race="Hispanic"),
]
config = CounterfactualBiasTestConfig(demographics=demos)
assert len(config.demographics) == 2
assert config.demographics[0].race == "Asian"
def test_extended_dimensions(self):
"""Test extended dimensions configuration."""
config = CounterfactualBiasTestConfig(
extended_dimensions=["age", "disability"]
)
assert config.extended_dimensions == ["age", "disability"]
def test_disabled_config(self):
"""Test disabled bias testing."""
config = CounterfactualBiasTestConfig(enabled=False)
assert config.enabled is False
class TestPerturbationTestConfig:
"""Tests for PerturbationTestConfig model."""
def test_default_values(self):
"""Test default configuration values."""
config = PerturbationTestConfig()
assert config.model == "gpt-4o-mini"
assert config.judge_model == "gpt-4o-mini"
assert config.max_relations is None
assert isinstance(config.execution, ExecutionConfig)
assert isinstance(config.jailbreak, JailbreakTestConfig)
assert isinstance(config.counterfactual_bias, CounterfactualBiasTestConfig)
def test_custom_models(self):
"""Test custom model configuration."""
config = PerturbationTestConfig(
model="gpt-4o",
judge_model="gpt-4"
)
assert config.model == "gpt-4o"
assert config.judge_model == "gpt-4"
def test_max_relations(self):
"""Test max_relations configuration."""
config = PerturbationTestConfig(max_relations=5)
assert config.max_relations == 5
config_all = PerturbationTestConfig(max_relations=None)
assert config_all.max_relations is None
def test_nested_config(self):
"""Test nested configuration objects."""
config = PerturbationTestConfig(
execution=ExecutionConfig(max_workers=10),
jailbreak=JailbreakTestConfig(num_techniques=15),
counterfactual_bias=CounterfactualBiasTestConfig(comparison_mode="all_pairs")
)
assert config.execution.max_workers == 10
assert config.jailbreak.num_techniques == 15
assert config.counterfactual_bias.comparison_mode == "all_pairs"
def test_model_dump(self):
"""Test model serialization."""
config = PerturbationTestConfig()
data = config.model_dump()
assert "model" in data
assert "judge_model" in data
assert "execution" in data
assert "jailbreak" in data
assert "counterfactual_bias" in data
class TestPresetConfigs:
"""Tests for preset configurations."""
def test_preset_keys(self):
"""Test preset configuration keys exist."""
assert "quick" in PRESET_CONFIGS
assert "standard" in PRESET_CONFIGS
assert "comprehensive" in PRESET_CONFIGS
def test_quick_preset(self):
"""Test quick preset configuration."""
config = PRESET_CONFIGS["quick"]
assert config.max_relations == 3
assert config.execution.max_workers == 3
assert config.jailbreak.num_techniques == 3
assert len(config.counterfactual_bias.demographics) == 2
assert config.counterfactual_bias.comparison_mode == "vs_baseline"
def test_standard_preset(self):
"""Test standard preset configuration."""
config = PRESET_CONFIGS["standard"]
assert config.max_relations == 10
assert config.execution.max_workers == 5
assert config.jailbreak.num_techniques == 10
assert config.counterfactual_bias.comparison_mode == "both"
def test_comprehensive_preset(self):
"""Test comprehensive preset configuration."""
config = PRESET_CONFIGS["comprehensive"]
assert config.max_relations is None
assert config.execution.max_workers == 10
assert config.execution.max_retries == 5
assert config.jailbreak.num_techniques == 20
assert len(config.counterfactual_bias.demographics) == 9
assert config.counterfactual_bias.extended_dimensions == ["age"]
class TestGetPresetConfig:
"""Tests for get_preset_config function."""
def test_valid_presets(self):
"""Test getting valid presets."""
for preset_name in ["quick", "standard", "comprehensive"]:
config = get_preset_config(preset_name)
assert isinstance(config, PerturbationTestConfig)
def test_invalid_preset(self):
"""Test invalid preset raises error."""
with pytest.raises(ValueError) as exc_info:
get_preset_config("invalid")
assert "Unknown preset" in str(exc_info.value)
def test_preset_is_copy(self):
"""Test that preset returns a copy."""
config1 = get_preset_config("standard")
config2 = get_preset_config("standard")
# Modify one should not affect the other
config1.max_relations = 999
assert config2.max_relations == 10
class TestCreateConfigFromDict:
"""Tests for create_config_from_dict function."""
def test_basic_dict(self):
"""Test creating config from basic dict."""
data = {
"model": "gpt-4",
"max_relations": 5
}
config = create_config_from_dict(data)
assert config.model == "gpt-4"
assert config.max_relations == 5
def test_nested_dict(self):
"""Test creating config from nested dict."""
data = {
"model": "gpt-4",
"execution": {"max_workers": 8},
"jailbreak": {"num_techniques": 15, "enabled": True},
"counterfactual_bias": {"comparison_mode": "all_pairs"}
}
config = create_config_from_dict(data)
assert config.execution.max_workers == 8
assert config.jailbreak.num_techniques == 15
assert config.counterfactual_bias.comparison_mode == "all_pairs"
def test_empty_dict(self):
"""Test creating config from empty dict uses defaults."""
config = create_config_from_dict({})
assert config.model == "gpt-4o-mini"
assert config.execution.max_workers == 5
class TestExtendedDemographics:
"""Tests for extended demographics constants."""
def test_extended_demographics_keys(self):
"""Test extended demographics keys exist."""
assert "age" in EXTENDED_DEMOGRAPHICS
assert "disability" in EXTENDED_DEMOGRAPHICS
assert "socioeconomic" in EXTENDED_DEMOGRAPHICS
def test_age_options(self):
"""Test age dimension options."""
assert len(EXTENDED_DEMOGRAPHICS["age"]) == 3
assert "young (20s)" in EXTENDED_DEMOGRAPHICS["age"]
assert "elderly (70s)" in EXTENDED_DEMOGRAPHICS["age"]
def test_disability_options(self):
"""Test disability dimension options."""
assert len(EXTENDED_DEMOGRAPHICS["disability"]) == 3
def test_socioeconomic_options(self):
"""Test socioeconomic dimension options."""
assert len(EXTENDED_DEMOGRAPHICS["socioeconomic"]) == 3