""" End-to-end tests for issue management CLI commands. Demonstrates: - CLI command testing with real processes - Environment isolation - Workflow validation - Output verification """ import pytest import subprocess import json import sys from pathlib import Path import time import os from tests.utils.assertions import assert_file_exists, assert_directory_exists, assert_file_contains @pytest.mark.e2e class TestIssueCommandsE2E: """End-to-end tests for issue management CLI commands.""" def test_show_issue_command_basic(self, isolated_environment): """Test basic issue show command.""" # Act result = subprocess.run( [sys.executable, "tddai_cli.py", "show-issue", "23"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) # Assert assert result.returncode == 0, f"Command failed with stderr: {result.stderr}" assert "Issue #23" in result.stdout or "issue 23" in result.stdout.lower() def test_show_issue_command_with_invalid_number(self, isolated_environment): """Test show issue command with invalid issue number.""" # Act result = subprocess.run( [sys.executable, "tddai_cli.py", "show-issue", "99999"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) # Assert - Should handle gracefully # Note: Depending on implementation, this might return 0 or 1 assert "not found" in result.stdout.lower() or "error" in result.stdout.lower() or "error" in result.stderr.lower() def test_workspace_status_command(self, isolated_environment): """Test workspace status command.""" # Act result = subprocess.run( [sys.executable, "tddai_cli.py", "workspace-status"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) # Assert assert result.returncode == 0 # Should show workspace information assert "workspace" in result.stdout.lower() or "status" in result.stdout.lower() @pytest.mark.slow def test_complete_issue_workflow(self, isolated_environment, test_workspace): """Test complete issue workflow from start to finish.""" workspace_dir = Path(isolated_environment["MARKITECT_WORKSPACE_DIR"]) workspace_dir.mkdir(exist_ok=True) # Step 1: Check initial workspace status result = subprocess.run( [sys.executable, "tddai_cli.py", "workspace-status"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) assert result.returncode == 0 # Step 2: Start working on an issue result = subprocess.run( [sys.executable, "tddai_cli.py", "start-issue", "42"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd(), timeout=30 # Prevent hanging ) # Verify the start command works (might create workspace) if result.returncode == 0: # If successful, check if workspace was created issue_workspace = workspace_dir / "issue_42" if issue_workspace.exists(): assert_directory_exists(issue_workspace) # Step 3: Check workspace status again result = subprocess.run( [sys.executable, "tddai_cli.py", "workspace-status"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) assert result.returncode == 0 # Step 4: Try to finish (cleanup) result = subprocess.run( [sys.executable, "tddai_cli.py", "finish-issue"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd(), timeout=30 ) # The finish command should work or provide meaningful feedback assert result.returncode in [0, 1] # Allow for various implementation states def test_list_open_issues_command(self, isolated_environment): """Test listing open issues.""" # Act result = subprocess.run( [sys.executable, "tddai_cli.py", "list-open-issues"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) # Assert assert result.returncode == 0 # Should return some form of issue listing (even if empty) output = result.stdout.strip() assert len(output) >= 0 # Any output is acceptable def test_cli_help_commands(self, isolated_environment): """Test CLI help functionality.""" # Test main help result = subprocess.run( [sys.executable, "tddai_cli.py", "--help"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) assert result.returncode == 0 assert "usage" in result.stdout.lower() or "commands" in result.stdout.lower() # Test specific command help result = subprocess.run( [sys.executable, "tddai_cli.py", "show-issue", "--help"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) assert result.returncode == 0 def test_cli_provides_helpful_error_for_unknown_commands(self, isolated_environment): """Test CLI provides helpful error message for unknown commands.""" # Act result = subprocess.run( [sys.executable, "tddai_cli.py", "invalid-command"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) # Assert - Should handle gracefully assert result.returncode != 0 assert "error" in result.stderr.lower() or "unknown" in result.stderr.lower() def test_cli_error_handling(self, isolated_environment): """Test CLI error handling for various scenarios.""" # Test with missing required argument result = subprocess.run( [sys.executable, "tddai_cli.py", "show-issue"], # Missing issue number env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) # Should provide helpful error message assert result.returncode != 0 assert len(result.stderr) > 0 or "error" in result.stdout.lower() @pytest.mark.parametrize("issue_number", ["1", "23", "100"]) def test_show_issue_command_multiple_issues(self, isolated_environment, issue_number): """Test show issue command with multiple issue numbers.""" # Act result = subprocess.run( [sys.executable, "tddai_cli.py", "show-issue", issue_number], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd(), timeout=15 ) # Assert - Command should execute without crashing assert result.returncode in [0, 1] # Allow for not found scenarios assert len(result.stdout + result.stderr) > 0 # Should provide some output def test_cli_performance(self, isolated_environment, performance_timer): """Test CLI command performance.""" # Act performance_timer.start() result = subprocess.run( [sys.executable, "tddai_cli.py", "workspace-status"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) performance_timer.stop() # Assert assert result.returncode == 0 # CLI commands should be reasonably fast assert performance_timer.elapsed < 10.0, f"CLI command took {performance_timer.elapsed:.2f}s" def test_cli_output_formatting(self, isolated_environment): """Test CLI output formatting and structure.""" # Test workspace status output result = subprocess.run( [sys.executable, "tddai_cli.py", "workspace-status"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd() ) if result.returncode == 0: output = result.stdout # Output should be readable and structured assert len(output.strip()) > 0 # Should not contain obvious error traces assert "Traceback" not in output assert "Exception" not in output def test_cli_environment_isolation(self, test_workspace): """Test that CLI commands work in isolated environment.""" # Create isolated environment isolated_env = { "MARKITECT_WORKSPACE_DIR": str(test_workspace / "isolated"), "MARKITECT_GITEA_URL": "http://isolated-gitea.com", "MARKITECT_REPO_OWNER": "isolated", "MARKITECT_REPO_NAME": "test", "PYTHONPATH": "." } # Update with current env to preserve PATH, etc. full_env = dict(os.environ) full_env.update(isolated_env) # Act result = subprocess.run( [sys.executable, "tddai_cli.py", "workspace-status"], env=full_env, capture_output=True, text=True, cwd=Path.cwd() ) # Assert - Should work with isolated environment assert result.returncode == 0 # Should use isolated workspace directory workspace_path = test_workspace / "isolated" workspace_path.mkdir(exist_ok=True) def test_multiple_cli_commands_can_execute_concurrently_without_conflicts(self, isolated_environment): """Test multiple CLI commands can execute concurrently without conflicts.""" import threading import queue results_queue = queue.Queue() def run_command(command_args): result = subprocess.run( command_args, env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd(), timeout=15 ) results_queue.put(result) # Start multiple commands concurrently commands = [ [sys.executable, "tddai_cli.py", "workspace-status"], [sys.executable, "tddai_cli.py", "show-issue", "1"], [sys.executable, "tddai_cli.py", "show-issue", "2"], ] threads = [] for cmd in commands: thread = threading.Thread(target=run_command, args=(cmd,)) threads.append(thread) thread.start() # Wait for all threads to complete for thread in threads: thread.join(timeout=20) # Collect results results = [] while not results_queue.empty(): results.append(results_queue.get()) # Assert assert len(results) == len(commands) # At least some commands should succeed successful_commands = [r for r in results if r.returncode == 0] assert len(successful_commands) > 0 @pytest.mark.smoke def test_cli_smoke_test(self, isolated_environment): """Basic smoke test for CLI functionality.""" # Test that the CLI script exists and is executable cli_script = Path("tddai_cli.py") assert_file_exists(cli_script) # Test basic command execution result = subprocess.run( [sys.executable, "tddai_cli.py", "--help"], env=isolated_environment, capture_output=True, text=True, cwd=Path.cwd(), timeout=10 ) # Should at least not crash assert result.returncode in [0, 1, 2] # Various help return codes assert len(result.stdout + result.stderr) > 0