Initial commit: waitlist microservice
Some checks failed
Test & Deploy Waitlist / test (push) Failing after 44s
Test & Deploy Waitlist / deploy (push) Has been skipped

This commit is contained in:
Roberto Musso
2026-04-11 10:35:53 +02:00
commit 4b2fefcf92
22 changed files with 841 additions and 0 deletions

109
tests/test_waitlist.py Normal file
View File

@@ -0,0 +1,109 @@
import pytest
import pytest_asyncio
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from app.main import app
from app.models import Base
from app.db import get_db
from app.rate_limit import _hits_store
# Use SQLite for tests (no Postgres dependency)
TEST_DB_URL = "sqlite+aiosqlite:///./test_waitlist.db"
@pytest_asyncio.fixture
async def db_session():
engine = create_async_engine(TEST_DB_URL)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
session_factory = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async with session_factory() as session:
yield session
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await engine.dispose()
@pytest_asyncio.fixture
async def client(db_session):
async def _override_db():
yield db_session
app.dependency_overrides[get_db] = _override_db
# Reset rate limiter state between tests
_hits_store.clear()
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac
app.dependency_overrides.clear()
@pytest.mark.asyncio
async def test_join_waitlist_success(client):
resp = await client.post(
"/api/v1/waitlist",
json={"email": "user@example.com"},
)
assert resp.status_code == 200
data = resp.json()
assert data["ok"] is True
assert "list" in data["message"].lower()
@pytest.mark.asyncio
async def test_duplicate_email_is_idempotent(client):
payload = {"email": "dup@example.com"}
r1 = await client.post("/api/v1/waitlist", json=payload)
r2 = await client.post("/api/v1/waitlist", json=payload)
assert r1.status_code == 200
assert r2.status_code == 200
@pytest.mark.asyncio
async def test_invalid_email_rejected(client):
resp = await client.post(
"/api/v1/waitlist",
json={"email": "not-an-email"},
)
assert resp.status_code == 422
@pytest.mark.asyncio
async def test_honeypot_silently_succeeds(client):
resp = await client.post(
"/api/v1/waitlist",
json={"email": "bot@spam.com", "website": "http://spam.site"},
)
# Honeypot field filled → validation error (max_length=0)
assert resp.status_code == 422
@pytest.mark.asyncio
async def test_missing_email_rejected(client):
resp = await client.post("/api/v1/waitlist", json={})
assert resp.status_code == 422
@pytest.mark.asyncio
async def test_health_endpoint(client):
resp = await client.get("/health")
assert resp.status_code == 200
assert resp.json()["status"] == "ok"
@pytest.mark.asyncio
async def test_rate_limit(client):
"""Submit more than the per-minute limit and expect 429."""
for i in range(6):
resp = await client.post(
"/api/v1/waitlist",
json={"email": f"rate{i}@example.com"},
)
# The 6th request should be rate-limited (limit is 5)
assert resp.status_code == 429
assert "Retry-After" in resp.headers