The SerDes Validation Framework includes a comprehensive testing infrastructure with 91+ core tests, advanced mock implementations, and multi-protocol integration testing.
The framework organizes tests into several categories:
Status: All passing, 0.83s execution time Purpose: Essential framework functionality validation
# Recommended command for development and CI/CD
python -m pytest tests/ -v --tb=short --ignore=tests/integration --ignore=tests/performance --ignore=tests/legacyTest Coverage:
- Basic Functionality: 16 tests - Core framework operations
- Basic Imports: 7 tests - Import system validation
- Certification Comprehensive: 5 tests - Certification workflows
- Daisy Chain Comprehensive: 5 tests - Multi-device testing
- Data Analysis: 4 tests - Signal analysis algorithms
- Framework Integration: 5 tests - Component integration
- Multi-Protocol: 4 tests - Cross-protocol functionality
- PCIe Analyzer: 4 tests - PCIe-specific validation
- Security Comprehensive: 5 tests - Security testing
- Summary Tests: 7 tests - Framework organization
- Tunneling Comprehensive: 20 tests - Protocol tunneling
- USB4 Comprehensive: 9 tests - USB4 functionality
Multi-Protocol Integration: 6/6 tests ✅ (Fully working) USB4 Integration: 0/15 tests ❌ (Needs enhanced mocks)
# Multi-protocol integration (working)
python -m pytest tests/integration/test_multi_protocol_integration.py -v
# USB4 integration (needs work)
python -m pytest tests/integration/test_usb4_integration.py -vUSB4 Performance Regression: 1/8 tests ✅
# Performance tests (partial functionality)
python -m pytest tests/performance/ -vStatus: All properly skipped Purpose: Maintain backward compatibility while avoiding conflicts
# Legacy tests are automatically ignored
python -m pytest tests/legacy/ -v # Will be skipped# Primary development command (91 tests passing)
python -m pytest tests/ -v --tb=short --ignore=tests/integration --ignore=tests/performance --ignore=tests/legacy
# Multi-protocol integration tests (6 tests passing)
python -m pytest tests/integration/test_multi_protocol_integration.py -v
# All comprehensive tests
python -m pytest tests/test_*_comprehensive.py -v
# Specific test categories
python -m pytest tests/test_basic_imports.py -v
python -m pytest tests/test_framework_integration.py -v
python -m pytest tests/test_usb4_comprehensive.py -v# Full command (91 passed, 25 failed from integration/performance)
python -m pytest tests/ -v --tb=shortThe framework automatically enables mock mode through environment variables:
# Set in pytest.ini
env =
SVF_MOCK_MODE=1
PYTHONPATH=srcclass ProtocolDetector:
def detect_protocol_from_signal(self, signal_data, sample_rate, voltage_range):
# Enhanced mock logic based on signal characteristics
if isinstance(signal_data, dict):
# USB4 multi-lane format - use first lane
signal_array = signal_data[0]['voltage']
else:
# Single signal array
signal_array = signal_data
signal_std = np.std(signal_array)
signal_levels = self._estimate_signal_levels(signal_array)
# PCIe: Higher voltage range (1.2V) and PAM4 levels
if voltage_range >= 1.0 and len(signal_levels) >= 3:
return ProtocolType.PCIE
# Ethernet: Medium voltage range (0.8V) and PAM4 levels
elif voltage_range == 0.8 and len(signal_levels) >= 3 and signal_std > 0.15:
return ProtocolType.ETHERNET_224G
# USB4: Lower voltage range (0.8V) and NRZ (2 levels)
elif voltage_range <= 0.8 and len(signal_levels) <= 2:
return ProtocolType.USB4
else:
return ProtocolType.USB4def generate_pcie_signal(self, duration: float = 5e-6):
"""Generate PCIe-like signal for testing"""
sample_rate = 200e9
num_samples = int(duration * sample_rate)
# PCIe 6.0 PAM4 signal (~32 GBaud)
symbol_rate = 32e9
pam4_levels = np.array([-0.6, -0.2, 0.2, 0.6])
symbols = np.random.choice(4, num_symbols)
# Generate realistic signal with noise
voltage = np.zeros(num_samples)
for i, symbol in enumerate(symbols):
start_idx = int(i * symbol_period * sample_rate)
end_idx = min(int((i + 1) * symbol_period * sample_rate), num_samples)
if end_idx > start_idx:
voltage[start_idx:end_idx] = pam4_levels[symbol]
# Add noise
voltage += 0.03 * np.random.randn(num_samples)
return voltage, {
'sample_rate': sample_rate,
'voltage_range': 1.2,
'expected_protocol': ProtocolType.PCIE,
'symbol_rate': symbol_rate,
'modulation': 'PAM4'
}# Available mock implementations
from tests.mocks.analyzer import DataAnalyzer
from tests.mocks.framework_integration import FrameworkIntegrator
from tests.mocks.pcie_analyzer import PCIeAnalyzer
from tests.mocks.multi_protocol import MultiProtocolComparator
from tests.mocks.usb4_comprehensive import USB4Validator[tool:pytest]
testpaths = tests
python_paths = src
addopts = -v --tb=short --ignore=tests/legacy --ignore=tests/hardware --ignore=tests/integration --ignore=tests/performance
env =
SVF_MOCK_MODE=1
PYTHONPATH=src
markers =
hardware: marks tests as requiring hardware (deselect with '-m "not hardware"')
visualization: marks tests as requiring visualization libraries
slow: marks tests as slow (deselect with '-m "not slow"')
integration: marks tests as integration tests# Hardware tests (automatically skipped in mock mode)
@pytest.mark.hardware
def test_real_hardware():
pass
# Visualization tests (conditional based on dependencies)
@pytest.mark.visualization
def test_plotting():
pass
# Slow tests (can be excluded for fast CI)
@pytest.mark.slow
def test_performance_benchmark():
pass
# Integration tests
@pytest.mark.integration
def test_multi_protocol_integration():
passimport pytest
import numpy as np
from serdes_validation_framework import create_validation_framework
class TestFrameworkIntegration:
"""Framework integration tests"""
def test_framework_creation(self):
"""Test framework creation and basic functionality"""
framework = create_validation_framework()
assert framework is not None
assert hasattr(framework, 'detect_protocol')
def test_protocol_detection(self):
"""Test protocol detection functionality"""
framework = create_validation_framework()
# Generate test signal
signal_data = np.random.randn(1000) * 0.1
protocol = framework.detect_protocol(
signal_data=signal_data,
sample_rate=100e9,
voltage_range=0.8
)
assert protocol is not Noneclass TestMultiProtocolIntegration:
"""Multi-protocol integration tests"""
def test_protocol_detection_accuracy(self, protocol_detector):
"""Test protocol detection accuracy across different protocols"""
test_cases = []
# Generate test signals for different protocols
pcie_signal, pcie_params = self.generate_pcie_signal()
ethernet_signal, ethernet_params = self.generate_ethernet_signal()
usb4_signal_data, usb4_params = self.generate_usb4_signal()
# Test detection for each protocol
detection_results = []
for protocol_name, signal, params in test_cases:
detected_protocol = protocol_detector.detect_protocol_from_signal(
signal_data=signal,
sample_rate=params['sample_rate'],
voltage_range=params['voltage_range']
)
detection_results.append({
'protocol_name': protocol_name,
'expected': params['expected_protocol'],
'detected': detected_protocol,
'correct': detected_protocol == params['expected_protocol']
})
# Verify detection accuracy
correct_detections = sum(1 for result in detection_results if result['correct'])
total_detections = len(detection_results)
accuracy = correct_detections / total_detections
# Require at least 66% accuracy (2 out of 3 protocols)
assert accuracy >= 0.66, f"Protocol detection accuracy {accuracy:.2%} below threshold"class TestPerformanceRegression:
"""Performance regression tests"""
def test_validation_performance(self):
"""Test validation performance benchmarks"""
framework = create_validation_framework()
# Generate large signal dataset
duration = 10e-6 # 10 μs
sample_rate = 200e9
num_samples = int(duration * sample_rate)
signal_data = np.random.randn(num_samples) * 0.1
start_time = time.time()
results = framework.run_auto_validation(
signal_data=signal_data,
sample_rate=sample_rate,
voltage_range=0.8
)
validation_time = time.time() - start_time
# Performance requirements
assert validation_time < 5.0, f"Validation took {validation_time:.2f}s, expected < 5.0s"
assert results is not Nonedef test_conditional_imports():
"""Test conditional import system"""
from serdes_validation_framework.protocols.usb4 import VISUALIZATION_AVAILABLE
# Test availability flags
assert isinstance(VISUALIZATION_AVAILABLE, bool)
# Test graceful degradation
if VISUALIZATION_AVAILABLE:
from serdes_validation_framework.protocols.usb4.visualization import USB4Visualizer
viz = USB4Visualizer()
assert viz is not None
else:
# Should handle missing dependencies gracefully
with pytest.raises(ImportError):
from serdes_validation_framework.protocols.usb4.visualization import USB4Visualizerdef test_error_handling():
"""Test error handling with invalid inputs"""
framework = create_validation_framework()
# Test with None data
with pytest.raises((ValueError, TypeError)):
framework.detect_protocol(None, 100e9, 0.8)
# Test with invalid parameters
with pytest.raises((ValueError, TypeError)):
framework.detect_protocol(np.array([1, 2, 3]), -100, 0.8)name: SerDes Framework Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -e .
- name: Run core tests
run: |
python -m pytest tests/ -v --tb=short --ignore=tests/integration --ignore=tests/performance --ignore=tests/legacy
- name: Run integration tests
run: |
python -m pytest tests/integration/test_multi_protocol_integration.py -v
- name: Generate coverage report
run: |
pip install pytest-cov
python -m pytest tests/ --cov=serdes_validation_framework --cov-report=html
- name: Upload coverage
uses: codecov/codecov-action@v1# Generate test reports
python -m pytest tests/ --html=report.html --self-contained-html
# Generate coverage report
python -m pytest tests/ --cov=serdes_validation_framework --cov-report=html
# Performance profiling
python -m pytest tests/ --profileimport logging
logging.basicConfig(level=logging.DEBUG)
# Enable framework debug logging
logger = logging.getLogger('serdes_validation_framework')
logger.setLevel(logging.DEBUG)# Use fresh instances for each test
@pytest.fixture
def fresh_framework():
"""Provide fresh framework instance for each test"""
return create_validation_framework()
# Clean up resources
@pytest.fixture(autouse=True)
def cleanup():
"""Automatic cleanup after each test"""
yield
# Cleanup code here
import gc
gc.collect()def test_mock_behavior():
"""Inspect mock behavior for debugging"""
from tests.mocks.analyzer import DataAnalyzer
analyzer = DataAnalyzer({'test': [1, 2, 3, 4, 5]})
# Check available methods
methods = [method for method in dir(analyzer) if not method.startswith('_')]
print(f"Available methods: {methods}")
# Test method behavior
stats = analyzer.compute_statistics('test')
print(f"Statistics result: {stats}")
assert 'mean' in stats
assert 'std' in stats- Keep core tests fast and reliable
- Isolate integration tests that may be flaky
- Use proper test markers for categorization
- Make mocks realistic and consistent
- Handle different input formats gracefully
- Provide configurable behavior for different scenarios
- Test both success and failure paths
- Validate error messages and types
- Ensure graceful degradation
- Keep core tests under 1 second total execution time
- Use appropriate timeouts for integration tests
- Profile and optimize slow tests
- Keep tests simple and focused
- Use descriptive test names and docstrings
- Maintain test documentation
- Import Errors: Ensure PYTHONPATH is set correctly
- Mock Mode Issues: Verify SVF_MOCK_MODE=1 is set
- Test Isolation: Use fresh fixtures for each test
- Performance Issues: Check for resource leaks
# Fix import issues
import sys
sys.path.insert(0, 'src')
# Verify mock mode
import os
assert os.environ.get('SVF_MOCK_MODE') == '1'
# Resource cleanup
@pytest.fixture(autouse=True)
def cleanup_resources():
yield
# Cleanup code
import gc
gc.collect()- Explore Mock Testing Guide for detailed mock usage
- Check API Reference for complete testing API
- See CI/CD Integration for automated testing setup
- Review Troubleshooting Guide for common issues