Skip to content

Commit effaff0

Browse files
committed
test: add comprehensive test framework with ci/cd
1 parent 89fb4f2 commit effaff0

File tree

12 files changed

+1416
-0
lines changed

12 files changed

+1416
-0
lines changed

.github/workflows/test.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: Tests and Quality Checks
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.10", "3.11", "3.12"]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Install uv
20+
uses: astral-sh/setup-uv@v3
21+
with:
22+
version: "latest"
23+
24+
- name: Set up Python ${{ matrix.python-version }}
25+
run: uv python install ${{ matrix.python-version }}
26+
27+
- name: Install dependencies
28+
run: |
29+
uv sync --all-extras --dev
30+
31+
- name: Run security tests
32+
run: |
33+
uv run pytest tests/unit/test_security_validation.py -v --tb=short
34+
35+
- name: Run configuration tests
36+
run: |
37+
uv run pytest tests/unit/test_configuration_validation.py -v --tb=short
38+
39+
- name: Run unit tests with coverage
40+
run: |
41+
uv run pytest tests/unit --cov=src/mcp_server_mas_sequential_thinking --cov-report=xml --cov-report=term-missing
42+
43+
- name: Run integration tests
44+
run: |
45+
uv run pytest tests/integration -v --tb=short
46+
47+
- name: Type checking with mypy
48+
run: |
49+
uv run mypy src --ignore-missing-imports
50+
51+
- name: Linting with ruff
52+
run: |
53+
uv run ruff check src tests
54+
55+
- name: Security scan with bandit
56+
run: |
57+
uv run bandit -r src -f json -o bandit-results.json || true
58+
59+
- name: Upload coverage to Codecov
60+
if: matrix.python-version == '3.11'
61+
uses: codecov/codecov-action@v3
62+
with:
63+
file: ./coverage.xml
64+
flags: unittests
65+
name: codecov-umbrella
66+
fail_ci_if_error: false
67+
68+
security:
69+
runs-on: ubuntu-latest
70+
name: Security Analysis
71+
72+
steps:
73+
- uses: actions/checkout@v4
74+
75+
- name: Install uv
76+
uses: astral-sh/setup-uv@v3
77+
78+
- name: Set up Python
79+
run: uv python install 3.11
80+
81+
- name: Install dependencies
82+
run: |
83+
uv sync --all-extras --dev
84+
85+
- name: Run security-focused tests
86+
run: |
87+
uv run pytest tests -m security -v --tb=short
88+
89+
- name: Security scan with safety
90+
run: |
91+
uv run safety check --json --output safety-results.json || true
92+
93+
- name: Dependency vulnerability scan
94+
run: |
95+
uv run pip-audit --format=json --output=audit-results.json || true

pytest.ini

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
[tool:pytest]
2+
# Pytest configuration for MCP Sequential Thinking Server
3+
4+
# Test discovery
5+
testpaths = tests
6+
python_files = test_*.py
7+
python_classes = Test*
8+
python_functions = test_*
9+
10+
# Test execution
11+
addopts =
12+
--strict-markers
13+
--strict-config
14+
--verbose
15+
--tb=short
16+
--color=yes
17+
--durations=10
18+
--cov=src/mcp_server_mas_sequential_thinking
19+
--cov-report=html:htmlcov
20+
--cov-report=term-missing
21+
--cov-report=xml
22+
--cov-fail-under=70
23+
24+
# Markers for test categorization
25+
markers =
26+
unit: Unit tests for individual components
27+
integration: Integration tests for component interactions
28+
security: Security-related tests
29+
config: Configuration and environment tests
30+
slow: Tests that take a long time to run
31+
asyncio: Tests that use asyncio
32+
33+
# Asyncio configuration
34+
asyncio_mode = auto
35+
36+
# Filtering
37+
filterwarnings =
38+
ignore::DeprecationWarning
39+
ignore::PendingDeprecationWarning
40+
ignore::UserWarning:agno.*
41+
42+
# Test output
43+
junit_family = xunit2
44+
junit_logging = all
45+
46+
# Coverage configuration
47+
[coverage:run]
48+
source = src/mcp_server_mas_sequential_thinking
49+
omit =
50+
*/tests/*
51+
*/test_*
52+
*/__pycache__/*
53+
*/migrations/*
54+
*/venv/*
55+
*/env/*
56+
57+
[coverage:report]
58+
exclude_lines =
59+
pragma: no cover
60+
def __repr__
61+
if self.debug:
62+
if settings.DEBUG
63+
raise AssertionError
64+
raise NotImplementedError
65+
if 0:
66+
if __name__ == .__main__.:
67+
class .*\bProtocol\):
68+
@(abc\.)?abstractmethod
69+
70+
[coverage:html]
71+
directory = htmlcov

run_tests.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#!/usr/bin/env python3
2+
"""Test runner script for MCP Sequential Thinking Server.
3+
4+
This script provides a convenient way to run tests with different
5+
configurations and options.
6+
"""
7+
8+
import argparse
9+
import subprocess
10+
import sys
11+
from pathlib import Path
12+
13+
14+
def run_command(cmd: list[str], description: str) -> int:
15+
"""Run a command and return its exit code."""
16+
print(f"\n🔍 {description}")
17+
print(f"Running: {' '.join(cmd)}")
18+
print("-" * 50)
19+
20+
result = subprocess.run(cmd, capture_output=False)
21+
22+
if result.returncode == 0:
23+
print(f"✅ {description} completed successfully")
24+
else:
25+
print(f"❌ {description} failed with exit code {result.returncode}")
26+
27+
return result.returncode
28+
29+
30+
def main():
31+
"""Main test runner function."""
32+
parser = argparse.ArgumentParser(
33+
description="Test runner for MCP Sequential Thinking Server",
34+
formatter_class=argparse.RawDescriptionHelpFormatter,
35+
epilog="""
36+
Examples:
37+
python run_tests.py # Run all tests
38+
python run_tests.py --unit # Run only unit tests
39+
python run_tests.py --integration # Run only integration tests
40+
python run_tests.py --security # Run only security tests
41+
python run_tests.py --coverage # Run tests with coverage report
42+
python run_tests.py --fast # Run tests without coverage
43+
python run_tests.py --debug # Run tests in debug mode
44+
"""
45+
)
46+
47+
# Test selection options
48+
parser.add_argument(
49+
"--unit", action="store_true",
50+
help="Run only unit tests"
51+
)
52+
parser.add_argument(
53+
"--integration", action="store_true",
54+
help="Run only integration tests"
55+
)
56+
parser.add_argument(
57+
"--security", action="store_true",
58+
help="Run only security tests"
59+
)
60+
parser.add_argument(
61+
"--config", action="store_true",
62+
help="Run only configuration tests"
63+
)
64+
65+
# Test execution options
66+
parser.add_argument(
67+
"--coverage", action="store_true",
68+
help="Generate coverage report"
69+
)
70+
parser.add_argument(
71+
"--fast", action="store_true",
72+
help="Run tests without coverage (faster)"
73+
)
74+
parser.add_argument(
75+
"--debug", action="store_true",
76+
help="Run tests in debug mode with verbose output"
77+
)
78+
parser.add_argument(
79+
"--parallel", action="store_true",
80+
help="Run tests in parallel"
81+
)
82+
parser.add_argument(
83+
"--html", action="store_true",
84+
help="Generate HTML coverage report"
85+
)
86+
87+
# Output options
88+
parser.add_argument(
89+
"--quiet", action="store_true",
90+
help="Reduce output verbosity"
91+
)
92+
parser.add_argument(
93+
"--junit", action="store_true",
94+
help="Generate JUnit XML report"
95+
)
96+
97+
args = parser.parse_args()
98+
99+
# Build pytest command
100+
cmd = ["uv", "run", "pytest"]
101+
102+
# Test selection
103+
if args.unit:
104+
cmd.append("tests/unit")
105+
elif args.integration:
106+
cmd.append("tests/integration")
107+
elif args.security:
108+
cmd.extend(["-m", "security"])
109+
elif args.config:
110+
cmd.extend(["-m", "config"])
111+
else:
112+
cmd.append("tests")
113+
114+
# Coverage options
115+
if args.coverage or (not args.fast and not args.debug):
116+
cmd.extend([
117+
"--cov=src/mcp_server_mas_sequential_thinking",
118+
"--cov-report=term-missing"
119+
])
120+
121+
if args.html:
122+
cmd.append("--cov-report=html")
123+
124+
# Output options
125+
if args.debug:
126+
cmd.extend(["-v", "-s", "--tb=long"])
127+
elif args.quiet:
128+
cmd.extend(["-q", "--tb=short"])
129+
else:
130+
cmd.extend(["-v", "--tb=short"])
131+
132+
# Parallel execution
133+
if args.parallel:
134+
cmd.extend(["-n", "auto"])
135+
136+
# JUnit reporting
137+
if args.junit:
138+
cmd.append("--junit-xml=test-results.xml")
139+
140+
# Run the tests
141+
description = "Running tests"
142+
if args.unit:
143+
description = "Running unit tests"
144+
elif args.integration:
145+
description = "Running integration tests"
146+
elif args.security:
147+
description = "Running security tests"
148+
elif args.config:
149+
description = "Running configuration tests"
150+
151+
exit_code = run_command(cmd, description)
152+
153+
# Additional commands based on options
154+
if args.coverage and exit_code == 0:
155+
print("\n📊 Coverage report generated!")
156+
if args.html:
157+
print("📄 HTML coverage report: htmlcov/index.html")
158+
159+
if exit_code == 0:
160+
print("\n🎉 All tests completed successfully!")
161+
162+
# Run additional quality checks if all tests pass
163+
print("\n🔍 Running additional quality checks...")
164+
165+
# Type checking
166+
type_check_result = run_command(
167+
["uv", "run", "mypy", "src", "--ignore-missing-imports"],
168+
"Type checking with mypy"
169+
)
170+
171+
# Linting
172+
lint_result = run_command(
173+
["uv", "run", "ruff", "check", "src", "tests"],
174+
"Linting with ruff"
175+
)
176+
177+
if type_check_result == 0 and lint_result == 0:
178+
print("\n✨ All quality checks passed!")
179+
else:
180+
print("\n⚠️ Some quality checks failed")
181+
exit_code = max(exit_code, type_check_result, lint_result)
182+
183+
sys.exit(exit_code)
184+
185+
186+
if __name__ == "__main__":
187+
main()

tests/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Test package for MCP Sequential Thinking Server.
2+
3+
This package contains unit tests, integration tests, and test fixtures
4+
for validating the functionality of the Sequential Thinking Server.
5+
"""
6+
7+
__version__ = "0.1.0"

tests/fixtures/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Test fixtures and test data."""

0 commit comments

Comments
 (0)