Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,61 @@ inventory/adithyakhamithkar
scripts
run-role.yml
ubuntu-desktop/roles/enemy-territory

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Testing
.pytest_cache/
.coverage
.coverage.*
htmlcov/
coverage.xml
*.cover
*.py,cover
.hypothesis/
.tox/
.nox/

# Virtual environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# IDE
.idea/
.vscode/
*.swp
*.swo
*~

# Poetry
poetry.lock

# Claude
.claude/*
93 changes: 93 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
[tool.poetry]
name = "ansible-playbooks"
version = "0.1.0"
description = "A collection of Ansible playbooks for various software installations and configurations"
authors = ["Your Name <[email protected]>"]
readme = "README.md"
packages = [{include = "scripts/python"}]

[tool.poetry.dependencies]
python = "^3.8"

[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
pytest-cov = "^5.0.0"
pytest-mock = "^3.14.0"

[tool.poetry.scripts]
test = "pytest:main"
tests = "pytest:main"

[tool.pytest.ini_options]
minversion = "8.0"
addopts = [
"-ra",
"--strict-markers",
"--strict-config",
"--cov=scripts.python",
"--cov-branch",
"--cov-report=term-missing:skip-covered",
"--cov-report=html",
"--cov-report=xml",
"--cov-fail-under=0", # Set to 80 when adding actual code tests
"-vv"
]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Tests that take a long time to run"
]
norecursedirs = [".git", ".tox", "dist", "build", "*.egg", "__pycache__"]
filterwarnings = [
"error",
"ignore::UserWarning",
"ignore::DeprecationWarning"
]

[tool.coverage.run]
source = ["scripts/python"]
branch = true
parallel = true
omit = [
"*/tests/*",
"*/test_*",
"*/__pycache__/*",
"*/site-packages/*",
"*/.venv/*",
"*/venv/*"
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
ignore_errors = true
precision = 2
show_missing = true
skip_covered = false
skip_empty = true
sort = "Cover"

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Testing package for ansible-playbooks
209 changes: 209 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
"""
Shared pytest fixtures and configuration for all tests.
"""
import os
import tempfile
from pathlib import Path
from typing import Generator, Dict, Any
import pytest


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""
Create a temporary directory for test files.

Yields:
Path: Path to the temporary directory
"""
with tempfile.TemporaryDirectory() as tmp_dir:
yield Path(tmp_dir)


@pytest.fixture
def mock_config() -> Dict[str, Any]:
"""
Provide a mock configuration dictionary for testing.

Returns:
Dict[str, Any]: Mock configuration data
"""
return {
"debug": False,
"version": "0.1.0",
"environment": "test",
"database": {
"host": "localhost",
"port": 5432,
"name": "test_db",
"user": "test_user",
"password": "test_password"
},
"api": {
"base_url": "http://localhost:8000",
"timeout": 30,
"retries": 3
}
}


@pytest.fixture
def sample_yaml_content() -> str:
"""
Provide sample YAML content for testing Ansible playbooks.

Returns:
str: Sample YAML content
"""
return """---
- name: Test Playbook
hosts: localhost
tasks:
- name: Test task
debug:
msg: "This is a test task"
"""


@pytest.fixture
def sample_json_data() -> Dict[str, Any]:
"""
Provide sample JSON data for testing.

Returns:
Dict[str, Any]: Sample JSON data
"""
return {
"items": [
{"id": 1, "name": "Item 1", "value": 100},
{"id": 2, "name": "Item 2", "value": 200},
{"id": 3, "name": "Item 3", "value": 300}
],
"metadata": {
"total": 3,
"page": 1,
"per_page": 10
}
}


@pytest.fixture
def mock_env_vars(monkeypatch) -> Dict[str, str]:
"""
Set up mock environment variables for testing.

Args:
monkeypatch: pytest monkeypatch fixture

Returns:
Dict[str, str]: Dictionary of environment variables that were set
"""
env_vars = {
"TEST_VAR": "test_value",
"DEBUG": "true",
"API_KEY": "mock_api_key_12345",
"DATABASE_URL": "postgresql://test:test@localhost/test"
}

for key, value in env_vars.items():
monkeypatch.setenv(key, value)

return env_vars


@pytest.fixture
def clean_environment(monkeypatch):
"""
Remove specific environment variables to ensure clean test environment.

Args:
monkeypatch: pytest monkeypatch fixture
"""
env_vars_to_remove = ["DEBUG", "API_KEY", "DATABASE_URL", "CONFIG_PATH"]

for var in env_vars_to_remove:
monkeypatch.delenv(var, raising=False)


@pytest.fixture(autouse=True)
def change_test_dir(request, monkeypatch):
"""
Change to test directory for the duration of the test.

Args:
request: pytest request fixture
monkeypatch: pytest monkeypatch fixture
"""
monkeypatch.chdir(request.fspath.dirname)


@pytest.fixture
def mock_file_system(temp_dir: Path) -> Dict[str, Path]:
"""
Create a mock file system structure for testing.

Args:
temp_dir: Temporary directory path

Returns:
Dict[str, Path]: Dictionary mapping file types to their paths
"""
# Create directory structure
dirs = {
"config": temp_dir / "config",
"data": temp_dir / "data",
"logs": temp_dir / "logs",
"scripts": temp_dir / "scripts"
}

for dir_path in dirs.values():
dir_path.mkdir(parents=True, exist_ok=True)

# Create some sample files
files = {
"config_file": dirs["config"] / "app.conf",
"data_file": dirs["data"] / "sample.json",
"log_file": dirs["logs"] / "app.log",
"script_file": dirs["scripts"] / "test_script.py"
}

# Write content to files
files["config_file"].write_text("# Configuration file\\nkey=value")
files["data_file"].write_text('{"test": "data"}')
files["log_file"].write_text("2024-01-01 00:00:00 INFO Test log entry")
files["script_file"].write_text("#!/usr/bin/env python\\nprint('test')")

return {**dirs, **files}


# Pytest hooks for better test organization and reporting
def pytest_configure(config):
"""
Configure pytest with custom settings.

Args:
config: pytest config object
"""
config.addinivalue_line(
"markers", "network: mark test as requiring network access"
)
config.addinivalue_line(
"markers", "database: mark test as requiring database access"
)


def pytest_collection_modifyitems(config, items):
"""
Modify test collection to add markers based on test location.

Args:
config: pytest config object
items: list of test items
"""
for item in items:
# Add unit marker to tests in unit directory
if "unit" in str(item.fspath):
item.add_marker(pytest.mark.unit)
# Add integration marker to tests in integration directory
elif "integration" in str(item.fspath):
item.add_marker(pytest.mark.integration)
1 change: 1 addition & 0 deletions tests/integration/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Integration tests package
Loading