Files
markitect-main/tests/test_l5_infrastructure_cache_monitoring.py
tegwick b13de9b2ad feat: Revolutionary Test Architecture - 7-Layer Organization with Advanced Testing Capabilities
ARCHITECTURAL MILESTONE: Complete transformation of test suite from issue-based to sophisticated
architectural layer organization with 348 tests across 7 layers (Foundation → Infrastructure →
Integration → Domain → Service → Application → Presentation).

Major Components:

🏗️ ARCHITECTURAL TEST ORGANIZATION:
• Renamed 23 test files to architectural layers (e.g. test_parser.py → test_l7_foundation_markdown_parsing.py)
• Created reverse dependency execution order for 60-80% faster feedback
• Foundation layer (10 tests, ~9s) provides immediate failure detection
• Complete dependency mapping across all 7 architectural layers

🎯 ADVANCED TEST RUNNERS:
• run_architectural_tests.py - Reverse dependency execution with performance metrics
• run_randomized_tests.py - Seed-based randomization for dependency detection
• Comprehensive error handling and colored output for optimal UX
• Support for layer-specific execution and early termination on failures

📋 COMPREHENSIVE DOCUMENTATION:
• ARCHITECTURE.md - 7-layer architecture blueprint with migration strategy
• CAPABILITIES.md - Complete inventory of 73+ system capabilities across 15 categories
• TEST_ARCHITECTURE.md - Detailed test execution strategy and naming conventions
• ARCHITECTURAL_CHAOS_TESTING_ISSUE.md - Chaos engineering gameplan (Issue #35)

🔧 MAKEFILE INTEGRATION:
• 15+ new testing targets (test-arch, test-foundation, test-random, etc.)
• Layer-specific execution (test-infrastructure, test-domain, test-service)
• Advanced options (test-quick, test-layers, test-random-repeat)
• Comprehensive help system with organized testing categories

🎲 RANDOMIZED TESTING:
• Seed-based reproducible test execution for debugging
• Multi-iteration testing to detect flaky tests and hidden dependencies
• Enhanced randomization support with pytest-randomly integration
• Performance analysis across different execution orders

🚀 PERFORMANCE OPTIMIZATION:
• Foundation-first execution prevents cascade failure debugging
• Quick testing (foundation + infrastructure) completes in ~22 seconds
• Layer isolation enables targeted debugging and development
• Optimal feedback loops for architectural development

This revolutionary testing infrastructure establishes MarkiTect as having enterprise-grade
test organization with architectural principles, performance optimization, and advanced
testing methodologies including chaos engineering foundations.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 12:18:25 +02:00

216 lines
8.6 KiB
Python

"""
Tests for Issue #13: Cache Management CLI Commands - cache-info functionality.
This module tests the cache-info command which displays cache statistics and effectiveness.
The cache-info command should provide detailed metrics including hit rate, memory usage,
file count, and performance monitoring data.
"""
import json
import os
import tempfile
from pathlib import Path
from unittest.mock import patch, MagicMock
import pytest
from click.testing import CliRunner
from markitect.cli import cli
from markitect.ast_cache import ASTCache
from markitect.database import DatabaseManager
class TestCacheInfoCommand:
"""Test suite for cache-info command functionality."""
def setup_method(self):
"""Set up test environment for each test."""
self.runner = CliRunner()
self.temp_dir = tempfile.mkdtemp()
self.cache_dir = Path(self.temp_dir) / ".ast_cache"
self.db_path = Path(self.temp_dir) / "test.db"
# Create test markdown file
self.test_file = Path(self.temp_dir) / "test.md"
self.test_file.write_text("""---
title: Test Document
author: Test Author
---
# Test Heading
This is a test document with some content.
## Section 1
Content for section 1.
## Section 2
More content here.
""")
def teardown_method(self):
"""Clean up after each test."""
import shutil
if Path(self.temp_dir).exists():
shutil.rmtree(self.temp_dir)
def test_cache_info_command_exists(self):
"""Test that cache-info command is available in CLI."""
# This test will initially fail until command is implemented
result = self.runner.invoke(cli, ['cache-info'])
# Should not return "No such command" error
assert "No such command" not in result.output
assert result.exit_code in [0, 1] # 0 for success, 1 for expected errors
def test_cache_info_displays_basic_statistics(self):
"""Test that cache-info displays basic cache statistics."""
# Setup: Create cache with some files
cache = ASTCache(self.cache_dir)
cache.cache_file(self.test_file)
# Execute command - patch the cache service instead of global Path
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
mock_cache_dir.return_value = self.cache_dir
result = self.runner.invoke(cli, ['cache-info'])
# Should show cache statistics
assert result.exit_code == 0
assert "Cache Directory:" in result.output
assert "Total Files:" in result.output
assert "Cache Size:" in result.output
def test_cache_info_shows_file_count(self):
"""Test that cache-info correctly reports number of cached files."""
# Setup: Create multiple cached files
cache = ASTCache(self.cache_dir)
# Create additional test files
test_file2 = Path(self.temp_dir) / "test2.md"
test_file2.write_text("# Another Test\n\nContent here.")
cache.cache_file(self.test_file)
cache.cache_file(test_file2)
# Execute command - mock CacheDirectoryService to return our test cache stats
with patch('markitect.cli.CacheDirectoryService') as mock_cache_service:
mock_service_instance = MagicMock()
mock_service_instance.get_cache_stats.return_value = {
'directory': str(self.cache_dir),
'total_files': 2,
'size_formatted': '1.2 KB'
}
mock_cache_service.return_value = mock_service_instance
result = self.runner.invoke(cli, ['cache-info'])
assert result.exit_code == 0
assert "Total Files: 2" in result.output
def test_cache_info_shows_memory_usage(self):
"""Test that cache-info displays memory usage information."""
# Setup: Create cache with content
cache = ASTCache(self.cache_dir)
cache.cache_file(self.test_file)
# Execute command - patch the cache service instead of global Path
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
mock_cache_dir.return_value = self.cache_dir
result = self.runner.invoke(cli, ['cache-info'])
assert result.exit_code == 0
# Should show memory/size information
assert any(keyword in result.output.lower() for keyword in ["size", "memory", "bytes", "kb", "mb"])
def test_cache_info_with_empty_cache(self):
"""Test cache-info behavior with empty cache directory."""
# Ensure cache directory exists but is empty
self.cache_dir.mkdir(exist_ok=True)
# Clear any existing files to ensure it's actually empty
for file in self.cache_dir.iterdir():
if file.is_file():
file.unlink()
# Execute command - patch the cache stats directly for this test
with patch('markitect.cache_service.CacheDirectoryService.get_cache_stats') as mock_stats:
mock_stats.return_value = {
'directory': str(self.cache_dir),
'total_files': 0,
'size_formatted': '0 B'
}
result = self.runner.invoke(cli, ['cache-info'])
assert result.exit_code == 0
assert "Total Files: 0" in result.output or "empty" in result.output.lower()
def test_cache_info_with_nonexistent_cache(self):
"""Test cache-info behavior when cache directory doesn't exist."""
# Use non-existent cache directory
nonexistent_dir = Path(self.temp_dir) / "nonexistent_cache"
# Execute command - patch the cache service instead of global Path
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
mock_cache_dir.return_value = nonexistent_dir
result = self.runner.invoke(cli, ['cache-info'])
# Should handle gracefully, either create directory or show appropriate message
assert result.exit_code in [0, 1]
assert "error" in result.output.lower() or "not found" in result.output.lower() or "0" in result.output
def test_cache_info_output_format(self):
"""Test that cache-info output is well-formatted and readable."""
# Setup: Create cache with content
cache = ASTCache(self.cache_dir)
cache.cache_file(self.test_file)
# Execute command - patch the cache service instead of global Path
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
mock_cache_dir.return_value = self.cache_dir
result = self.runner.invoke(cli, ['cache-info'])
assert result.exit_code == 0
# Should have structured output with clear labels
lines = result.output.strip().split('\n')
assert len(lines) >= 3 # Should have multiple lines of info
# Should contain key information
output_lower = result.output.lower()
assert "cache" in output_lower
assert any(char in result.output for char in [':']) # Should have label:value format
def test_cache_info_performance_metrics(self):
"""Test that cache-info includes performance-related metrics."""
# Setup: Create cache and simulate usage
cache = ASTCache(self.cache_dir)
cache.cache_file(self.test_file)
# Load cached AST to simulate cache hit
cache.load_cached_ast(self.test_file)
# Execute command - patch the cache service instead of global Path
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
mock_cache_dir.return_value = self.cache_dir
result = self.runner.invoke(cli, ['cache-info'])
assert result.exit_code == 0
# Should include performance-related information
# This might include cache effectiveness, file ages, etc.
assert len(result.output.strip()) > 50 # Should be substantial output
def test_cache_info_with_verbose_flag(self):
"""Test cache-info with verbose flag showing detailed information."""
# Setup: Create cache with content
cache = ASTCache(self.cache_dir)
cache.cache_file(self.test_file)
# Execute command with verbose flag - patch the cache service instead of global Path
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
mock_cache_dir.return_value = self.cache_dir
result = self.runner.invoke(cli, ['--verbose', 'cache-info'])
# Verbose mode might show more detailed information
# For now, just ensure command works
assert result.exit_code in [0, 1]