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
51 changes: 50 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,50 @@
*.pyc
*.pyc
__pycache__/
*.pyo
*.pyd
.Python
env/
venv/
ENV/
.venv/
pip-log.txt
pip-delete-this-directory.txt

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

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

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

# Claude
.claude/*

# OS
.DS_Store
Thumbs.db
838 changes: 838 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

95 changes: 95 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
[tool.poetry]
name = "mangodb"
version = "0.1.0"
description = "A Python server application"
authors = ["Your Name <you@example.com>"]
readme = "README.rst"
package-mode = false

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

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

[tool.poetry.scripts]

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = [
"tests",
]
python_files = [
"test_*.py",
"*_test.py",
"tests.py"
]
python_classes = [
"Test*",
"*Tests"
]
python_functions = [
"test_*"
]
addopts = [
"-ra",
"--strict-markers",
"--cov=server",
"--cov-branch",
"--cov-report=term-missing:skip-covered",
"--cov-report=html",
"--cov-report=xml",
"--cov-fail-under=80",
"-vv"
]
markers = [
"unit: marks tests as unit tests (fast, isolated)",
"integration: marks tests as integration tests (may require external resources)",
"slow: marks tests as slow (deselect with '-m \"not slow\"')"
]

[tool.coverage.run]
source = ["."]
omit = [
"*/tests/*",
"*/test_*",
"*/__pycache__/*",
"*/site-packages/*",
"*/distutils/*",
"*/venv/*",
"*/virtualenv/*",
".venv/*",
"conftest.py",
"setup.py"
]

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

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

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

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
5 changes: 5 additions & 0 deletions run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
# Helper script to run tests with poetry

# Pass all arguments to pytest
poetry run pytest "$@"
Empty file added tests/__init__.py
Empty file.
125 changes: 125 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import pytest
import tempfile
import shutil
import os
import socket
from unittest.mock import Mock, patch


@pytest.fixture
def temp_dir():
"""Create a temporary directory that is cleaned up after the test."""
temp_path = tempfile.mkdtemp()
yield temp_path
shutil.rmtree(temp_path, ignore_errors=True)


@pytest.fixture
def temp_file():
"""Create a temporary file that is cleaned up after the test."""
fd, path = tempfile.mkstemp()
os.close(fd)
yield path
try:
os.unlink(path)
except FileNotFoundError:
pass


@pytest.fixture
def mock_socket():
"""Provide a mock socket object for testing network operations."""
mock_sock = Mock(spec=socket.socket)
mock_sock.makefile.return_value = Mock()
mock_sock.sendall.return_value = None
return mock_sock


@pytest.fixture
def mock_environ():
"""Provide a mock environment for testing environment variables."""
with patch.dict(os.environ, clear=True):
yield os.environ


@pytest.fixture
def mock_gevent_server():
"""Mock gevent StreamServer for testing server creation."""
with patch('gevent.server.StreamServer') as mock_server:
instance = Mock()
mock_server.return_value = instance
yield instance


@pytest.fixture
def mock_file_operations():
"""Mock file operations for testing without actual file I/O."""
mock_open = Mock()
mock_file = Mock()
mock_open.return_value = mock_file

with patch('builtins.open', mock_open):
yield {
'open': mock_open,
'file': mock_file
}


@pytest.fixture
def mock_threading():
"""Mock threading components for testing concurrent operations."""
with patch('threading.Lock') as mock_lock, \
patch('threading.Condition') as mock_condition:

lock_instance = Mock()
condition_instance = Mock()

mock_lock.return_value = lock_instance
mock_condition.return_value = condition_instance

yield {
'lock': lock_instance,
'condition': condition_instance,
'Lock': mock_lock,
'Condition': mock_condition
}


@pytest.fixture(autouse=True)
def reset_modules():
"""Reset module-level state between tests."""
import sys
modules_to_reset = [m for m in sys.modules.keys() if m.startswith('server')]
for module in modules_to_reset:
if module in sys.modules:
del sys.modules[module]
yield


@pytest.fixture
def client_socket_data():
"""Provide sample data for client socket communication."""
return {
'valid_commands': [
'BYE\r\n',
'WAIT\r\n',
'PUT some data here\r\n',
'GET key\r\n'
],
'invalid_commands': [
'INVALID\r\n',
'\r\n',
'MALFORMED',
]
}


@pytest.fixture
def server_config():
"""Provide test configuration for the server."""
return {
'host': '0.0.0.0',
'port': 27017,
'durable': False,
'eventual': False
}
Empty file added tests/integration/__init__.py
Empty file.
76 changes: 76 additions & 0 deletions tests/test_setup_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import pytest
import sys
import os


class TestSetupValidation:
"""Validate that the testing infrastructure is properly configured."""

@pytest.mark.unit
def test_pytest_installed(self):
"""Verify pytest is available."""
assert 'pytest' in sys.modules or pytest.__version__

@pytest.mark.unit
def test_pytest_cov_installed(self):
"""Verify pytest-cov is available."""
try:
import pytest_cov
assert pytest_cov
except ImportError:
pytest.skip("pytest-cov not yet installed")

@pytest.mark.unit
def test_pytest_mock_installed(self):
"""Verify pytest-mock is available."""
try:
import pytest_mock
assert pytest_mock
except ImportError:
pytest.skip("pytest-mock not yet installed")

@pytest.mark.unit
def test_fixtures_available(self, temp_dir, temp_file, mock_socket):
"""Verify custom fixtures are available."""
assert os.path.exists(temp_dir)
assert os.path.dirname(temp_file)
assert hasattr(mock_socket, 'sendall')

@pytest.mark.unit
def test_markers_registered(self, pytestconfig):
"""Verify custom markers are registered."""
markers = pytestconfig.getini('markers')
marker_names = [m.split(':')[0].strip() for m in markers]
assert 'unit' in marker_names
assert 'integration' in marker_names
assert 'slow' in marker_names

@pytest.mark.unit
def test_server_module_importable(self):
"""Verify the server module can be imported."""
try:
import server
assert hasattr(server, 'mangodb')
assert hasattr(server, 'StreamServer')
except ImportError as e:
pytest.fail(f"Failed to import server module: {e}")

@pytest.mark.integration
def test_coverage_configured(self):
"""Verify coverage is properly configured."""
import coverage
cov = coverage.Coverage()
config = cov.config

# Check that coverage is configured to measure our code
assert config.source is not None or config.source_pkgs is not None

@pytest.mark.unit
def test_test_directory_structure(self):
"""Verify test directory structure is correct."""
test_root = os.path.dirname(os.path.abspath(__file__))

assert os.path.exists(os.path.join(test_root, '__init__.py'))
assert os.path.exists(os.path.join(test_root, 'conftest.py'))
assert os.path.exists(os.path.join(test_root, 'unit', '__init__.py'))
assert os.path.exists(os.path.join(test_root, 'integration', '__init__.py'))
Empty file added tests/unit/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions tests/unit/test_server_basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest
from unittest.mock import Mock, patch, MagicMock
import os


class TestServerBasic:
"""Basic unit tests for server module to demonstrate testing setup."""

@pytest.mark.unit
def test_environment_variables_default(self):
"""Test default environment variable values."""
with patch.dict(os.environ, {}, clear=True):
import server
assert server.MANGODB_DURABLE == False
assert server.MANGODB_EVENTUAL == False

@pytest.mark.unit
def test_environment_variables_set(self):
"""Test environment variables when set."""
with patch.dict(os.environ, {'MANGODB_DURABLE': 'True', 'MANGODB_EVENTUAL': 'True'}):
# Force reload of module to pick up env vars
import importlib
import server
importlib.reload(server)

assert server.MANGODB_DURABLE == 'True'
assert server.MANGODB_EVENTUAL == 'True'