Private
Public Access
Phase 4: Web Push notifications (pywebpush + VAPID)
Backend: PushSubscription model/migration, VAPID config + `cli.py generate-vapid-keys`, push_service.send_push_to_user (upsert-by-endpoint subscribe/unsubscribe, auto-cleanup of expired 404/410 subscriptions), /api/push/* router, and ConnectionManager now tracks connected user IDs per room so chat.py can push only to offline members after broadcasting to online ones. Two test-infra bugs found and fixed along the way: send_push_to_user takes the caller's AsyncSession and is awaited inline rather than fired via asyncio.create_task with its own session (background tasks were outliving the test event loop); and the ws_client fixture now uses NullPool to eliminate a connection-pool checkout race that was failing WS tests intermittently. Frontend: service worker rebuilt with vite-plugin-pwa's injectManifest strategy (custom src/sw.ts) so it can add push/notificationclick handlers alongside the existing precaching and StaleWhileRevalidate routes ported over from generateSW. New subscribe/unsubscribe flow (lib/push.ts, api/push.ts) with a toggle in the account menu. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ from alembic.config import Config
|
||||
from fastapi.testclient import TestClient
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.pool import NullPool
|
||||
|
||||
from app.database import get_db
|
||||
from app.main import create_app
|
||||
@@ -84,8 +85,17 @@ def ws_client():
|
||||
# the `db_session`/`app` fixtures' engine, which belongs to pytest's
|
||||
# loop. No per-test rollback here (see test_ws_chat.py for the
|
||||
# unique-name convention that keeps tests independent without it).
|
||||
#
|
||||
# poolclass=NullPool: with pooling, a WS test that does more than one
|
||||
# DB round trip per message (e.g. the offline-push lookup) can hit a
|
||||
# race where the pooled connection returned by the WS handler's session
|
||||
# close hasn't finished being checked back in before the test's next
|
||||
# (synchronous, same-portal) REST call checks a connection back out --
|
||||
# surfaces as "connection is closed". A fresh connection per session
|
||||
# sidesteps it; fine for tests, not something prod needs (prod isn't
|
||||
# juggling a background portal thread against the main test thread).
|
||||
application = create_app()
|
||||
test_engine = create_async_engine(TEST_DATABASE_URL)
|
||||
test_engine = create_async_engine(TEST_DATABASE_URL, poolclass=NullPool)
|
||||
test_session_factory = async_sessionmaker(test_engine, expire_on_commit=False)
|
||||
|
||||
async def _get_db():
|
||||
|
||||
Reference in New Issue
Block a user