SurfSense/surfsense_backend/tests
CREDO23 aab95b9130 refactor(agents): move tools package to app/agents/shared (slice 6)
Relocate the entire new_chat/tools/ package (62 files incl. registry, hitl, MCP
cluster, and all connector subpackages: gmail/slack/discord/teams/drive/etc.)
to the shared kernel. The package turned out to be a clean cohesive cluster:
its only references to non-tools new_chat modules were comments, and its
middleware deps were already flipped to shared in slice 5c.

Flip 33 live importers (multi-agent, flows, routes, services, anonymous_agent,
tests). Re-export shims remain for the frozen single-agent stack: a package
__init__ mirroring the public surface (new_chat.__init__ imports it) plus
invalid_tool + registry submodule shims (chat_deepagent imports those).

Resolves slice 5c's two transient back-edges: shared/middleware/action_log
(TYPE_CHECKING ToolDefinition) and tool_call_repair (local INVALID_TOOL_NAME)
now point at app.agents.shared.tools.
2026-06-04 13:11:56 +02:00
..
e2e refactor(agents): move tools package to app/agents/shared (slice 6) 2026-06-04 13:11:56 +02:00
fixtures remove stale ElectricSQL references from changelog and test fixtures 2026-03-24 17:07:11 +02:00
integration refactor(agents): move tools package to app/agents/shared (slice 6) 2026-06-04 13:11:56 +02:00
unit refactor(agents): move tools package to app/agents/shared (slice 6) 2026-06-04 13:11:56 +02:00
utils feat: implement task dispatcher for document processing 2026-02-26 23:55:47 +05:30
__init__.py feat: Add end-to-end tests for document upload pipeline and shared test utilities 2026-02-25 16:39:45 +05:30
conftest.py feat: add should_summarize parameter to task dispatchers 2026-02-26 19:12:37 -08:00
README.md test: add notifications unit tests and conventions doc 2026-06-03 21:53:06 +02:00

Tests

How the backend test suite is organized and the conventions to follow when adding tests.

Layout: type-first, module-mirrored

Tests are split by type at the top level, and each type mirrors the app/ module tree inside:

tests/
├── conftest.py                  # global fixtures + DATABASE_URL pinning
├── unit/                        # pure logic: no DB, no app, no network
│   └── notifications/
│       ├── api/test_transform.py
│       └── service/
│           ├── messages/test_connector_indexing.py
│           └── test_metadata.py
└── integration/                 # real PostgreSQL (pgvector)
    ├── conftest.py              # async engine, transactional db_session, db_user, ...
    └── notifications/
        ├── conftest.py          # module-scoped fixtures (e.g. transactional client)
        └── test_*_handler.py

To find a feature's tests, look under tests/<type>/<same path as app/>.

Unit vs integration

  • @pytest.mark.unit — pure, fast, no I/O. Test behavior through a public function's inputs/outputs.
  • @pytest.mark.integration — requires a real database. Run with AUTH_TYPE=LOCAL.

Maximize logic covered by unit tests; keep integration tests for what genuinely needs the DB (persistence, SQL filters, scoping, HTTP wiring).

Principles

  • Behavior, not implementation. Assert observable outputs (returned values, persisted rows, HTTP responses), never private helpers. Tests should survive a refactor.
  • Functional core / imperative shell. Put pure decision logic in a side-effect-free module (e.g. app/notifications/service/messages/) so it is unit-testable; keep the persistence shell thin and cover it with a few integration tests.
  • One responsibility per test file, mirroring the slice it covers.
  • Mock only at system boundaries (external APIs, brokers), never internal collaborators. Prefer dependency overrides and the transactional db_session over mocks.

Fixtures

conftest.py is scoped to its directory and below. Keep truly global fixtures in tests/conftest.py; put module-specific fixtures in that module's conftest.py so a DB fixture never loads for a pure unit test.

For API integration tests, override get_async_session and current_active_user to ride the test's transactional db_session (see tests/integration/notifications/conftest.py): rows seeded in the test and rows read via the endpoint share one transaction that rolls back automatically.

Import mode

The suite uses --import-mode=importlib with pythonpath = ["."] (see pyproject.toml). This lets test files share basenames across modules (e.g. many test_api.py) without __init__.py boilerplate; new test directories do not need an __init__.py.

Running

# fast unit tests
uv run pytest -m unit

# integration (needs Postgres + pgvector)
AUTH_TYPE=LOCAL uv run pytest -m integration

# a single module's tests
uv run pytest tests/unit/notifications