50d2348b36
- tests/MERGE_CHECKLIST.md → tests/ALL_TESTS.md (git rename, updated header + index of sub-files) - tests/backend_tests.md — §1–9, §18 (auth, users, admin, groups, appearance, service health, plugins, AI/doc settings, infra/security) - tests/frontend_tests.md — §19 (UI & routing) - tests/doc-service_tests.md — §10–16 (upload/processing, list/filtering, slide-over, sharing, categories, bulk actions, watch directory) - tests/ai-service_tests.md — §17 (AI queue & providers) - CLAUDE.md: updated merge checklist section, file tree, and self-update checkpoint with mandatory test-file update rule - settings.local.json: added docker inspect/ps, curl, lsof, git merge/branch/log/diff/status/config/mv permissions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11 KiB
11 KiB
Backend Tests
Tests covering the FastAPI gateway (backend:8000): auth, user/profile management, admin (users/groups/appearance), service health, plugin system, AI settings, document settings, and infrastructure/security.
Full combined suite: tests/ALL_TESTS.md
Test environment: Feature stack at http://localhost:$PORT (see CLAUDE.md §Feature branch workflow).
Admin credentials: any superuser account created during stack setup.
Regular user credentials: a second non-admin account for permission boundary tests.
Legend
| Symbol | Meaning |
|---|---|
| ✅ | Pass |
| ❌ | Fail |
| — | N/A for this change |
1. Authentication
| # | Test | Steps | Expected |
|---|---|---|---|
| 1.1 | Register new account | POST /api/auth/register with valid email + strong password |
201; user row created; login works immediately |
| 1.2 | Password policy — too short | Register with 7-char password | 422 with validation error |
| 1.3 | Password policy — no uppercase | Register with all-lowercase password | 422 with validation error |
| 1.4 | Password policy — no special char | Register without special character | 422 with validation error |
| 1.5 | Password policy — common word | Register with password containing "password" | 422 with validation error |
| 1.6 | Duplicate email | Register with an already-used email | 400 |
| 1.7 | Login — valid credentials | POST /api/auth/login with correct email + password |
200; access_token returned |
| 1.8 | Login — wrong password | POST /api/auth/login with wrong password |
401 |
| 1.9 | Login — inactive account | Admin deactivates user; attempt login | 401 |
| 1.10 | JWT expiry respected | Manually craft token with exp in the past; call any protected route |
401 |
| 1.11 | Logout clears session | Click Logout in UI; try navigating to / |
Redirected to /login |
| 1.12 | Unauthenticated redirect | Open / without a token in localStorage |
Redirected to /login |
2. User — Profile & Preferences
| # | Test | Steps | Expected |
|---|---|---|---|
| 2.1 | Fetch own profile | GET /api/profile/me |
200; profile auto-created if first request |
| 2.2 | Update profile fields | PUT /api/profile/me with full_name, phone, position, address, date_of_birth |
200; fields persisted; visible on /profile page |
| 2.3 | Invalid phone format | PUT /api/profile/me with letters in phone field |
422 |
| 2.4 | Future date of birth | PUT /api/profile/me with DOB = tomorrow |
422 |
| 2.5 | DOB before 1900 | PUT /api/profile/me with DOB = 1899-12-31 |
422 |
| 2.6 | Fetch dashboard preferences | GET /api/users/me/preferences |
200; app_ids list |
| 2.7 | Pin an app | Dashboard → pencil button → press + on a card → save |
Card appears in pinned grid on next load |
| 2.8 | Unpin an app | Dashboard → pencil button → press − on a pinned card → save |
Card removed from pinned grid |
| 2.9 | Pin limit (50) | PATCH /api/users/me/preferences with 51 app IDs |
422 |
| 2.10 | Color mode — user pref | User sets mode to "dark"; reload page | Dark theme applied; preference persists across sessions |
| 2.11 | Color mode — system fallback | User has NULL color_mode; admin default_mode = "light" | Light theme applied |
3. Admin — Users
| # | Test | Steps | Expected |
|---|---|---|---|
| 3.1 | List all users | Admin → /admin/users |
All registered users shown in table |
| 3.2 | Create user | Admin clicks "Create user"; fills form | 201; new user appears in list; can log in |
| 3.3 | Toggle user active | Admin clicks toggle on active user | User deactivated; login returns 401 |
| 3.4 | Delete user | Admin deletes a user | 204; user no longer in list; their documents remain (orphaned) |
| 3.5 | Non-admin access | Regular user navigates to /admin/users |
Redirected to /login |
| 3.6 | Admin 404 semantics | Regular user calls GET /api/admin/users via curl |
404 (not 403) |
4. Admin — Groups
| # | Test | Steps | Expected |
|---|---|---|---|
| 4.1 | List groups | Admin → /admin/groups |
All groups shown with member count |
| 4.2 | Create group | Fill name + description → submit | Group appears in list; {group_name}-admin bootstrap group also exists (auto-created on service start) |
| 4.3 | Edit group | Click edit on group → change name → save | Name updated |
| 4.4 | Delete group | Delete group | 204; group gone; memberships cascade-deleted |
| 4.5 | Add member | Open group → search user → add | 204; user appears in member list |
| 4.6 | Remove member | Click remove on a member | User removed from group |
| 4.7 | Duplicate group name | Create group with name that already exists | 400 / validation error shown |
| 4.8 | Non-admin access | Regular user calls GET /api/admin/groups |
404 |
| 4.9 | Set group admin role | Admin → group detail → tick "Group admin" checkbox on a member → save | PATCH /api/admin/groups/{id}/members/{user_id}/admin with {"is_group_admin": true} returns 200; badge shown in member list |
| 4.10 | Unset group admin role | Admin unticks "Group admin" on an existing group admin member | Returns 200; badge removed; user loses group-admin privileges |
5. Admin — Appearance
| # | Test | Steps | Expected |
|---|---|---|---|
| 5.1 | List themes | Admin → /admin/appearance |
Built-in themes + any custom themes shown |
| 5.2 | Switch active theme | Select a different theme → save | All users see the new theme on next load |
| 5.3 | Create custom theme | Admin → create theme. Required fields: id (slug), label, light (CSS vars object), dark (CSS vars object) |
201; theme appears in selector; can be activated |
| 5.4 | Edit custom theme | Admin edits colour values on a custom theme | Colours update live after activation |
| 5.5 | Delete custom theme | Admin deletes a custom theme | 204; theme gone from selector; active theme reverts to default |
| 5.6 | Set default mode | PATCH /api/settings/appearance with {"theme": "<id>", "default_mode": "dark"} (both fields required) |
200; new users without a personal preference see dark mode |
6. Service Health & Dashboard
| # | Test | Steps | Expected |
|---|---|---|---|
| 6.1 | Services endpoint | GET /api/services (authenticated) |
Returns health status for doc-service and ai-service |
| 6.2 | Healthy service card | Both services running → /apps page. API response uses healthy: true (boolean), not status: "healthy" |
Cards show "Available" badge; clicking navigates to the app |
| 6.3 | Unhealthy service card | Stop doc-service container → wait 30s → /apps |
Doc-service card dimmed, "Unavailable", not clickable |
| 6.4 | Service recovery | Restart stopped container → wait 30s | Card returns to "Available" |
| 6.5 | Dashboard pinned cards | Pin a service → go to / |
Pinned card appears in home grid |
| 6.6 | Customize mode | Click pencil on dashboard → toggle cards | Pinned list updates after save |
7. Plugin System
| # | Test | Steps | Expected |
|---|---|---|---|
| 7.1 | List plugins | GET /api/plugins (authenticated) |
Returns accessible plugins for current user |
| 7.2 | Superuser sees all plugins | Log in as admin → GET /api/plugins |
All registered service plugins returned |
| 7.3 | Group member sees plugin | Add user to doc-service-admin group → GET /api/plugins |
doc-service plugin returned |
| 7.4 | Unpermitted user hidden | Regular user not in any admin group → GET /api/plugins |
Empty list (plugins hidden, not 403) |
| 7.5 | Manifest fetch | GET /api/plugins/doc-service/manifest as permitted user |
JSON Schema + access rules returned |
| 7.6 | Settings read | GET /api/plugins/doc-service/settings |
Current doc-service plugin settings returned |
| 7.7 | Settings write | PATCH /api/plugins/doc-service/settings with valid payload |
200; setting persisted to volume |
| 7.8 | Unpermitted settings access | Regular user GET /api/plugins/doc-service/settings |
404 |
8. AI Service Settings
| # | Test | Steps | Expected |
|---|---|---|---|
| 8.1 | Read AI config | Admin (or ai-service-admin member) → GET /api/settings/ai |
Config returned; API keys masked |
| 8.2 | Update provider | PATCH /api/settings/ai with provider = "anthropic" + valid key |
200; config persisted |
| 8.3 | Test connection | POST /api/settings/ai/test with valid config |
200; success response from provider |
| 8.4 | Test connection — bad key | POST /api/settings/ai/test with wrong API key |
502 or error detail |
| 8.5 | Read system prompts | GET /api/settings/system-prompts |
All registered service prompts returned |
| 8.6 | Update system prompt | PATCH /api/settings/system-prompts/doc-service with new prompt text |
200; doc-service picks up new prompt within 30s |
| 8.7 | Non-admin access | Regular user calls any /api/settings/ai endpoint |
404 |
| 8.8 | ai-service-admin delegation |
Non-superuser added to ai-service-admin group → accesses AI settings page |
Page loads; can read and write settings |
9. Document Service Settings
| # | Test | Steps | Expected |
|---|---|---|---|
| 9.1 | Read upload limits | GET /api/settings/documents/limits (admin or doc-service-admin) |
max_pdf_bytes returned |
| 9.2 | Update upload limit | PATCH /api/settings/documents/limits with new value |
200; upload of oversized PDF now rejected with 413 |
| 9.3 | Non-admin access | Regular user calls GET /api/settings/documents/limits |
404 |
| 9.4 | Settings page loads | Admin navigates to /apps/documents/settings |
Upload limits section + watch directory config visible |
| 9.5 | doc-service-admin delegation |
Non-superuser added to doc-service-admin → navigates to settings page |
Page loads; settings editable |
18. Infrastructure & Security
| # | Test | Steps | Expected |
|---|---|---|---|
| 18.1 | Non-root containers | docker inspect <container> --format '{{.Config.User}}' for each service |
Returns 1001 (or 70 for db) |
| 18.2 | No host ports in prod | docker compose up --build -d → docker ps |
Only port 80 (frontend) exposed; no 8000/8001/8010/5432 |
| 18.3 | backend-net isolation | curl http://localhost:8000 from host in prod |
Connection refused |
| 18.4 | Pre-commit hook runs | Stage a file with eval("x") → git commit |
Commit blocked; security_check.py output shown |
| 18.5 | Pre-commit hook — clean code | Normal commit | Hook passes; commit succeeds |
| 18.6 | JWT algorithm none rejected | Craft token with "alg": "none" → call protected route |
401 |
| 18.7 | XSS — input sanitation | Enter <script>alert(1)</script> in title/name fields |
Value stored as plain text; not executed in UI |
| 18.8 | SQL injection attempt | Pass '; DROP TABLE documents; -- as search param |
200 with empty results; no DB error |
| 18.9 | CORS | curl -H "Origin: http://evil.com" http://localhost/api/users/me |
Request blocked or access-control-allow-origin not set for that origin |
| 18.10 | Config volume persistence | Restart all containers | AI provider config + doc limits survive restart |
| 18.11 | Migration auto-apply | Start fresh stack | Both alembic upgrade head chains run without error; all tables created |