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
62 changes: 58 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,70 @@
# IDE and cache
.cache
.idea
.vscode
*__pycache__*
*.pyc
*.pyo
*.pyd
.Python

# Environment
.env*
venv/
.venv/
env/
ENV/

# Logs
log
test/log
test/**/log
.pytest_cache
.vscode
*__pycache__*
*.log

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

# Claude
.claude/*

# Build artifacts
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Poetry
poetry.lock

# Data
data
test/data
test/**/data

# pipenv
# pipenv (legacy)
Pipfile
Pipfile.lock

# OS files
.DS_Store
Thumbs.db
*.swp
*.swo
*~
101 changes: 101 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
[tool.poetry]
name = "midjourney-api"
version = "0.1.0"
description = "Midjourney API integration project"
authors = ["Your Name <[email protected]>"]
readme = "README.md"
packages = [{include = "app"}, {include = "lib"}, {include = "task"}, {include = "util"}]

[tool.poetry.dependencies]
python = "^3.8"
discord-py = "2.2.3"
fastapi = "0.95"
python-dotenv = "1.0.0"
uvicorn = "0.22.0"
pydantic = "~1.10.7"
aiohttp = "~3.8.4"
loguru = "0.7.0"
aiofiles = "23.1.0"
python-multipart = "0.0.6"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-mock = "^3.11.1"
pytest-asyncio = "^0.21.1"

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

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--verbose",
"--strict-markers",
"--cov=app",
"--cov=lib",
"--cov=task",
"--cov=util",
"--cov-report=html",
"--cov-report=xml",
"--cov-report=term-missing",
"--cov-fail-under=80",
]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Slow running tests",
]
filterwarnings = [
"error",
"ignore::UserWarning",
"ignore::DeprecationWarning",
]

[tool.coverage.run]
source = ["app", "lib", "task", "util"]
omit = [
"*/tests/*",
"*/__pycache__/*",
"*/.venv/*",
"*/venv/*",
"*/.tox/*",
"*/.coverage*",
"*/htmlcov/*",
"*/dist/*",
"*/build/*",
"*/.pytest_cache/*",
"*/__init__.py",
]

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

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

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

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Empty file added tests/__init__.py
Empty file.
180 changes: 180 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
"""Shared pytest fixtures for testing."""
import os
import tempfile
from pathlib import Path
from typing import Generator, Dict, Any
import pytest
from unittest.mock import Mock, MagicMock


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

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


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

Returns:
Dict[str, str]: Dictionary of test environment variables
"""
test_env = {
"DISCORD_TOKEN": "test_discord_token",
"API_KEY": "test_api_key",
"DEBUG": "true",
"LOG_LEVEL": "DEBUG",
"PORT": "8000",
}

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

return test_env


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

Returns:
Dict[str, Any]: Test configuration dictionary
"""
return {
"app": {
"name": "test_app",
"version": "0.1.0",
"debug": True,
},
"discord": {
"token": "test_token",
"guild_id": "123456789",
"channel_id": "987654321",
},
"api": {
"base_url": "http://localhost:8000",
"timeout": 30,
"retry_attempts": 3,
},
}


@pytest.fixture
def mock_discord_client():
"""Create a mock Discord client for testing.

Returns:
Mock: Mocked Discord client
"""
client = MagicMock()
client.user = MagicMock()
client.user.id = 123456789
client.user.name = "TestBot"
client.is_ready.return_value = True
return client


@pytest.fixture
def mock_fastapi_client():
"""Create a mock FastAPI test client.

Returns:
Mock: Mocked FastAPI test client
"""
client = MagicMock()
client.base_url = "http://testserver"
return client


@pytest.fixture
def sample_discord_message():
"""Create a sample Discord message for testing.

Returns:
Dict[str, Any]: Sample Discord message data
"""
return {
"id": "1234567890",
"content": "Test message content",
"author": {
"id": "987654321",
"username": "testuser",
"discriminator": "1234",
},
"channel_id": "111222333",
"guild_id": "444555666",
"timestamp": "2023-01-01T00:00:00.000Z",
}


@pytest.fixture
def sample_api_response():
"""Create a sample API response for testing.

Returns:
Dict[str, Any]: Sample API response data
"""
return {
"status": "success",
"data": {
"id": "response_123",
"result": "Test result",
"metadata": {
"timestamp": "2023-01-01T00:00:00.000Z",
"version": "1.0.0",
},
},
"error": None,
}


@pytest.fixture(autouse=True)
def reset_environment(monkeypatch):
"""Reset environment variables before each test.

This fixture runs automatically before each test to ensure
a clean environment state.
"""
# Clear any existing environment variables that might interfere
env_vars_to_clear = [
"DISCORD_TOKEN",
"API_KEY",
"DATABASE_URL",
"REDIS_URL",
]

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


@pytest.fixture
def mock_async_context():
"""Provide a mock async context manager.

Useful for testing async context managers without actual I/O.
"""
class MockAsyncContext:
async def __aenter__(self):
return self

async def __aexit__(self, exc_type, exc_val, exc_tb):
pass

return MockAsyncContext()


@pytest.fixture
def capture_logs(caplog):
"""Capture and provide access to log messages during tests.

Returns:
caplog: Pytest caplog fixture configured for the test
"""
caplog.set_level("DEBUG")
return caplog
Empty file added tests/integration/__init__.py
Empty file.
Loading