Add comprehensive testing infrastructure
- Testing strategy document - Unit tests for GPS validator - Integration test conftest with fixtures - Sample .sub files and manifests - Comprehensive Termux testing guide - Test directory structure
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
"""
|
||||
Pytest Configuration and Shared Fixtures
|
||||
|
||||
Provides shared test fixtures for unit and integration tests
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from src.database.models import Base
|
||||
from src.core.storage import LocalStorage
|
||||
from config.settings import settings
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# DATABASE FIXTURES
|
||||
# =============================================================================
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def test_db_engine():
|
||||
"""
|
||||
Create test database engine
|
||||
|
||||
Uses in-memory SQLite for fast tests
|
||||
"""
|
||||
# Use SQLite in-memory for tests
|
||||
engine = create_engine("sqlite:///:memory:", echo=False)
|
||||
|
||||
# Create all tables
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
yield engine
|
||||
|
||||
# Cleanup
|
||||
Base.metadata.drop_all(engine)
|
||||
engine.dispose()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def db_session(test_db_engine):
|
||||
"""
|
||||
Database session fixture
|
||||
|
||||
Creates a new session for each test and rolls back after
|
||||
"""
|
||||
Session = sessionmaker(bind=test_db_engine)
|
||||
session = Session()
|
||||
|
||||
yield session
|
||||
|
||||
session.rollback()
|
||||
session.close()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# STORAGE FIXTURES
|
||||
# =============================================================================
|
||||
|
||||
@pytest.fixture
|
||||
def temp_storage_dir():
|
||||
"""
|
||||
Temporary storage directory
|
||||
|
||||
Creates a temp dir and cleans up after test
|
||||
"""
|
||||
temp_dir = tempfile.mkdtemp(prefix="giglez_test_")
|
||||
|
||||
yield Path(temp_dir)
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_storage(temp_storage_dir):
|
||||
"""
|
||||
Test storage backend (LocalStorage)
|
||||
|
||||
Uses temporary directory
|
||||
"""
|
||||
return LocalStorage(base_path=str(temp_storage_dir))
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# API FIXTURES
|
||||
# =============================================================================
|
||||
|
||||
@pytest.fixture
|
||||
def test_client():
|
||||
"""
|
||||
FastAPI test client
|
||||
|
||||
Provides TestClient for API endpoint testing
|
||||
"""
|
||||
from src.api.main import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# SAMPLE DATA FIXTURES
|
||||
# =============================================================================
|
||||
|
||||
@pytest.fixture
|
||||
def sample_sub_file_key():
|
||||
"""Sample .sub file content (KEY format)"""
|
||||
return """Filetype: Flipper SubGhz Key File
|
||||
Version: 1
|
||||
Frequency: 433920000
|
||||
Preset: FuriHalSubGhzPresetOok270Async
|
||||
Protocol: Princeton
|
||||
Bit: 24
|
||||
Key: 00 00 00 00 00 95 D5 D4
|
||||
TE: 400
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_sub_file_raw():
|
||||
"""Sample .sub file content (RAW format)"""
|
||||
return """Filetype: Flipper SubGhz RAW File
|
||||
Version: 1
|
||||
Frequency: 315000000
|
||||
Preset: FuriHalSubGhzPresetOok650Async
|
||||
Protocol: RAW
|
||||
RAW_Data: 2980 -240 520 -980 520 -980 1000 -500 480 -1020
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_manifest():
|
||||
"""Sample upload manifest"""
|
||||
return {
|
||||
"session_uuid": "test-session-001",
|
||||
"captures": [
|
||||
{
|
||||
"filename": "test.sub",
|
||||
"latitude": 40.7128,
|
||||
"longitude": -74.0060,
|
||||
"accuracy": 5.0,
|
||||
"altitude": 10.5,
|
||||
"timestamp": "2026-01-12T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_gps_coordinates():
|
||||
"""Sample GPS coordinates (valid)"""
|
||||
return [
|
||||
(40.7128, -74.0060, 5.0, "NYC"),
|
||||
(51.5074, -0.1278, 8.0, "London"),
|
||||
(35.6762, 139.6503, 3.0, "Tokyo"),
|
||||
(-33.8688, 151.2093, 10.0, "Sydney"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def invalid_gps_coordinates():
|
||||
"""Invalid GPS coordinates for testing"""
|
||||
return [
|
||||
(91.0, 0.0, 5.0, "Latitude > 90"),
|
||||
(-91.0, 0.0, 5.0, "Latitude < -90"),
|
||||
(0.0, 181.0, 5.0, "Longitude > 180"),
|
||||
(0.0, -181.0, 5.0, "Longitude < -180"),
|
||||
(0.0, 0.0, 5.0, "Null Island"),
|
||||
(40.7128, -74.0060, 100.0, "Poor accuracy"),
|
||||
]
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PYTEST MARKERS
|
||||
# =============================================================================
|
||||
|
||||
def pytest_configure(config):
|
||||
"""Register custom pytest markers"""
|
||||
config.addinivalue_line("markers", "unit: Unit tests (fast, no external dependencies)")
|
||||
config.addinivalue_line("markers", "integration: Integration tests (database, API)")
|
||||
config.addinivalue_line("markers", "manual: Manual tests (human verification required)")
|
||||
config.addinivalue_line("markers", "slow: Slow tests (skip in CI)")
|
||||
Reference in New Issue
Block a user