Airweave 后端测试体系实战:E2E 冒烟测试的目录结构、环境配置与运行指南
【免费下载链接】airweaveOpen-source context retrieval layer for AI agents项目地址: https://gitcode.com/GitHub_Trending/ai/airweave
Airweave 是一个开源的 AI Agent 上下文检索层(context retrieval layer),其后端由 FastAPI 提供服务,测试体系以端到端(E2E)冒烟测试为核心。本文基于 backend/tests/README.md 展开,结合 backend/tests/e2e 下的真实源码,完整讲解后端测试目录的规划方式、E2E 测试的环境搭建、.env.test配置项含义、pytest 运行参数与标记体系,以及共享 Fixture 和冒烟用例的实现细节。读完本文,你将能独立为本仓库配置并运行整套 E2E 冒烟测试,并能读懂其测试基础设施的设计思路。
一、测试目录结构总览
原文档给出了后端测试目录的整体规划:
tests/ ├── e2e/ │ ├── config.py # Test configuration │ ├── conftest.py # Pytest fixtures │ ├── requirements.txt # Dependencies │ └── smoke/ # E2E test files ├── unit/ # Unit tests (future) └── integration/ # Integration tests (future)对照当前仓库实际内容(位于 backend/tests),该规划已基本落地:
- backend/tests/e2e/config.py:基于 Pydantic Settings 的类型安全测试配置类
TestSettings,统一管理全部环境变量; - backend/tests/e2e/conftest.py:提供异步 HTTP 客户端、测试 Collection、各数据源连接(Stripe / Todoist / Asana / Slack / Gmail 等)与 Auth Provider 等共享 Fixture;
- backend/tests/e2e/requirements.txt:E2E 测试依赖清单;
- backend/tests/e2e/smoke:33 个冒烟测试文件,覆盖集合管理、搜索(v1/v2/流式)、同步、限流、Webhook、OAuth 等核心链路;
- backend/tests/e2e/pytest.ini:E2E 目录独立的 pytest 配置;
- backend/tests/unit与backend/tests/integration:原文档标注为 "future",当前仓库已分别补充了单元测试与集成测试目录,前者覆盖 adapters / api / core / domains / platform / schemas / search 等模块,后者覆盖 api 与 storage 两条链路。
除 E2E 目录自身的 conftest 外,仓库根级 backend/conftest.py 会在导入任何airweave模块前通过os.environ.setdefault注入FIRST_SUPERUSER、ENCRYPTION_KEY、STATE_SECRET、POSTGRES_*、AUTH_ENABLED=false、DENSE_EMBEDDER等测试环境变量,并注册pytest_asyncio插件与全套fake_*依赖注入 Fixture(如fake_sync_service、fake_billing_service),供单测与领域测试共用。
二、环境准备与依赖安装
原文档给出的 E2E 测试启动步骤为:
cd tests/e2e pip install -r requirements.txt # 创建 .env.test 并填入你的凭据 # 运行测试 pytest smoke/依赖清单(backend/tests/e2e/requirements.txt)面向异步 E2E 场景做了针对性选型:
- pytest >= 7.4.0:测试框架主体;
- pytest-asyncio >= 0.24.0:异步测试支持,配合
asyncio_mode = auto无需逐个标注装饰器; - pytest-xdist >= 3.3.0:并行分发,
-n auto即可按 CPU 核数并行; - httpx >= 0.25.0:异步 HTTP 客户端,用于直接请求后端 API;
- pydantic >= 2.0.0 / pydantic-settings >= 2.0.0:
TestSettings的配置解析底座; - python-dotenv >= 1.0.0:加载
.env.test环境文件; - qdrant-client >= 1.13.3:本地向量库客户端,用于校验索引结果;
- fastapi==0.104.1 / uvicorn[standard]==0.24.0:固定版本的本地服务栈;
- pyngrok >= 5.1.0:本地隧道工具,用于暴露本机端点供外部验证(如 Webhook)。
三、环境变量配置:.env.test与 TestSettings
E2E 测试通过.env.test文件注入全部敏感配置。仓库提供了可直接拷贝的模板 backend/tests/e2e/env.test.example,其字段名必须与 config.py 中TestSettings的定义严格一致(模板注释中明确说明 "names must match TestSettings in config.py")。
TestSettings继承pydantic_settings.BaseSettings,model_config指定env_file=".env.test"、extra="ignore"(多余变量忽略而不报错),并定义了如下配置组:
| 配置项 | 默认值 | 说明 |
|---|---|---|
TEST_ENV | local | 测试目标环境,枚举local/dev/prod |
AIRWEAVE_API_KEY | 无 | dev/prod 环境的 API Key |
TEST_STRIPE_API_KEY | 必填 | Stripe API Key,校验必须以sk_开头且长度 ≥ 10 |
OPENAI_API_KEY | 无 | OpenAI Key(embedding,可选) |
TEST_NOTION_TOKEN | 必填 | Notion OAuth Token(token 注入场景) |
TEST_GOOGLE_CLIENT_ID/TEST_GOOGLE_CLIENT_SECRET | 必填 | Google OAuth(BYOC 场景) |
TEST_PIPEDREAM_*(5 项) | 必填 | Pipedream 的 project / account / external user / client 凭据 |
TEST_TRELLO_CONSUMER_KEY/_SECRET | 必填 | Trello OAuth1 凭据 |
TEST_AUTH_PROVIDER_NAME | composio | 校验必须等于composio |
TEST_COMPOSIO_API_KEY | 必填 | Composio API Key |
TEST_COMPOSIO_*_AUTH_CONFIG_ID/_ACCOUNT_ID | 无 | 各数据源(Asana / Slack / Gmail / Todoist / Notion / Google Drive)在 Composio 侧的认证配置 |
SKIP_STARTUP | false | 为true时跳过start.sh与容器健康检查 |
STRICT_MODE | false | 为true时要求所有可选环境变量必须存在 |
DEFAULT_TIMEOUT | 30 | API 请求默认超时(秒) |
SYNC_TIMEOUT | 60 | 同步操作超时(秒) |
MAX_WORKERS | 4 | 测试最大并行 worker 数 |
其中两个字段通过@field_validator做了运行时校验:TEST_STRIPE_API_KEY必须以sk_开头且长度不小于 10;TEST_AUTH_PROVIDER_NAME若传入非composio值会直接抛出ValueError(config.py),从配置层杜绝了错误的环境组合。
TestSettings还暴露了几个派生属性,测试代码通过这些属性间接访问环境:
api_url:按TEST_ENV映射 API 地址——local为http://localhost:8001,dev为https://api.dev-airweave.com,prod为https://api.airweave.ai(config.py);requires_api_key:仅当TEST_ENV为dev/prod时为真;api_headers:始终携带Content-Type: application/json与accept: application/json,在 dev/prod 环境下自动追加x-api-key头;qdrant_url:仅本地环境返回http://localhost:6333;test_env/test_notion_token/default_timeout/sync_timeout等小写别名属性,用于向后兼容。
文件末尾的settings = TestSettings()创建了全局单例,conftest 与各测试模块均直接导入该实例。
四、运行 E2E 冒烟测试
原文档与 backend/tests/e2e/README.md 共同给出了完整的运行方式:
# 全部冒烟测试 pytest smoke/ # 只跑单个文件 pytest smoke/test_sources.py # 常用选项 pytest smoke/ -v # 详细输出 pytest smoke/ -n auto # 按 CPU 核数并行(pytest-xdist) pytest smoke/ -x # 首个失败即停止 pytest smoke/ -m "not slow" # 跳过慢速测试backend/tests/e2e/pytest.ini 为 E2E 目录预置了默认行为:
- 发现规则:
testpaths = .、python_files = test_*.py、python_classes = Test*、python_functions = test_*; - 异步配置(关键):
asyncio_mode = auto与asyncio_default_fixture_loop_scope = function,文件注释强调这组配置对防止事件循环问题至关重要; - addopts:
-v、--tb=short、--strict-markers、--maxfail=5、--color=yes、--durations=10——即失败最多容忍 5 个、并输出耗时 Top10,便于定位慢用例; - 并行执行:注释说明使用
pytest -n auto或pytest -n 4搭配 pytest-xdist。
仓库根级 backend/pytest.ini 则限定testpaths = tests、设置pythonpath = .(保证airweave包可导入)、asyncio_mode = auto,并注册了integration/rate_limit/api_rate_limit标记,与 E2E 目录的标记体系互补。
五、测试标记(Markers)与智能调度
E2E 冒烟测试通过自定义标记进行分类,标记定义同时存在于 pytest.ini 与 conftest.py 的pytest_configure钩子中(后者还注册了requires_composio、local_only、critical等补充标记):
| 标记 | 语义 |
|---|---|
slow | 慢速测试,可用-m "not slow"剔除 |
requires_sync | 依赖已完成的同步数据 |
requires_temporal | 依赖 Temporal(仅本地) |
critical | 必须通过的关键路径测试 |
requires_openai | 依赖 OpenAI API Key |
requires_composio | 依赖 Composio Auth Provider |
rate_limit | 消耗限流配额,最后执行 |
api_rate_limit | 消耗 API 限流配额,CI 中跳过 |
local_only | 需要本地环境(直接访问存储) |
更值得关注的是pytest_collection_modifyitems钩子(conftest.py)实现的智能排序:
- 当
TEST_ENV != "local"时,自动为所有local_only用例追加 skip 标记,避免在远程环境误碰本地存储; - 将
rate_limit用例从整体集合中分离并重排到全部用例之后执行,保证配额类测试不会被并行 worker 干扰,其余用例保持原顺序。
同时 conftest 会打印重排统计信息(如Test order modified: N rate_limit tests will run last),便于在 CI 日志中确认调度结果。
六、共享 Fixture 体系:从 API 客户端到多档位数据源连接
backend/tests/e2e/conftest.py 是 E2E 测试的基础设施核心,按作用域与用途可分为几类:
6.1 客户端与资源基础
anyio_backend(session):固定返回asyncio,统一异步后端;config(session):直接暴露settings单例;api_client:基于httpx.AsyncClient,自动注入base_url=settings.api_url、api_headers与timeout(默认 30s),并开启follow_redirects;collection(function):POST/collections/创建一个以时间戳命名的测试 Collection,测试结束后 DELETE 清理,属于"即建即销"模式;module_api_client/module_collection:与上面等价但跨整个模块共享,减少重复创建开销。
6.2 真实第三方数据源连接
针对不同测试诉求,conftest 提供多档位的真实数据源连接 Fixture:
composio_auth_provider:通过 Composio 创建认证提供者。采用get-or-create + 最多 3 次重试策略(conftest.py):先 GET/auth-providers/connections/composio-test,404 后再 POST 创建;若因 pytest-xdist 多 worker 竞争触发UniqueViolation/duplicate key,则指数退避后重试 GET 复用其他 worker 已创建的实例,最后兜底再 GET 一次;source_connection_fast:Todoist 快速连接,期望 30 秒内完成同步;source_connection_medium:Asana 中等速度连接,期望 1~3 分钟完成同步;source_connection_slack_federated:Slack联邦搜索连接(不落库同步,查询时实时检索 Slack API),缺少配置时pytest.skip优雅跳过;source_connection_continuous_slow:Gmail 慢速连接,基于游标字段、同步至少 5 分钟;timed_source_connection_fast/timed_source_connection_medium:仓库内置的TimedSource 模拟数据源,不依赖任何外部服务——fast 档 2 秒生成 20 个实体(用于验证同步完成后的状态),medium 档 30 秒生成 100 个实体(用于验证同步中途取消),适合无第三方凭据的 CI 环境;module_source_connection_stripe:模块级 Stripe 连接,创建时sync_immediately: true立即同步,随后以 2 秒间隔轮询连接状态与sync.last_job最多 3 分钟等待同步完成,再通过搜索接口query: "customer OR invoice OR payment"最多 12 次重试验证数据真实可检索(同步完成 ≠ 已索引),最后才 yield 给测试使用;pipedream_auth_provider/pipedream_rate_limit_auth_provider:分别用于常规测试与限流专项测试的 Pipedream 认证提供者,限流版使用独立的环境变量凭据避免配额互相挤占。
所有连接 Fixture 都遵循同一模式:测试结束后"best effort"清理(删除失败仅静默忽略),避免失败残留污染后续运行。
6.3 Webhook 接收端点
smoke/conftest.py 提供了webhook_receiverFixture:通过postb.in(免费 HTTP Request Bin,接受任意 POST 并返回 200)为每个用例创建独立 bin。其设计动机是:该 URL 既可从测试宿主机访问,也可从 Docker 容器内访问,从而绕开host.docker.internal/ ngrok / 防火墙等本地联调难题;每个测试独立 bin 则避免 pytest-xdist 并发时req/shift弹出式读取导致用例间"偷取"投递。Fixture 还会对新 bin 做一次 warm-up 请求(新建 bin 首次请求可能较慢)。
七、冒烟测试覆盖范围
backend/tests/e2e/smoke 目录下的用例覆盖了 Airweave 后端的主要业务面:
- 集合与实体:
test_collections.py、test_collection_access_control.py、test_entity_definitions.py - 连接与认证:
test_source_connections_auth_provider.py、test_source_connections_direct_auth.py、test_source_connections_oauth.py、test_source_connections_template_configs.py、test_source_connections_token_injection.py、test_connect_sessions.py、test_special_tokens.py - 搜索:
test_search.py、test_search_filters.py、test_search_v2.py、test_search_v2_federated.py、test_search_v2_filters.py、test_search_v2_stream.py、test_federated_search.py - 同步与调度:
test_continuous_sync.py、test_running_and_cancelling_syncs.py、test_schedule_pause_unpause.py、test_schedules.py、test_sync_*(含在相关文件中) - 限流:
test_rate_limiting.py、test_source_rate_limiting.py - Webhook 与事件:
test_webhooks.py、test_pubsub.py - 清理与杂项:
test_cleanup.py、test_storage_backend.py、test_stub_file_types.py、test_exception_stub.py、test_organization_setup.py、test_sources.py
八、真实用例解剖:搜索与清理测试
以 test_search.py 为例,其核心用例test_search_with_all_defaults只传一个query字段调用统一的搜索端点POST /collections/{readable_collection_id}/search,通过断言completion字段间接验证defaults.yml中的默认行为(expand_query: true、rerank: true、generate_answer: true、retrieval_strategy: hybrid、temporal_relevance: 0.3、limit: 1000)真正生效——即"测试即文档",默认配置的变动会被测试捕获。
test_cleanup.py 则系统验证资源删除语义:删除带数据与不带数据的 Source Connection / Collection、级联删除(先建 Collection 再建连接后删除 Collection)、删除后列表不再包含、按"先连接后集合"的顺序清理,以及对不存在的资源返回 404 的错误处理。其中test_delete_collection断言status_code in [200, 404],反映了级联删除实现下"幂等清理"的容忍策略。
九、常见问题与最佳实践
- 依赖与后端未就绪:首次运行前需
pip install -r requirements.txt,并确保本地后端(http://localhost:8001)与依赖服务(PostgreSQL、Qdrant、Temporal)已启动;SKIP_STARTUP=true可跳过启动脚本与容器健康检查,适用于手动已启动环境的场景。 - 凭据缺失:
TestSettings中的TEST_STRIPE_API_KEY、TEST_NOTION_TOKEN、Composio 系列为必填,缺失会导致启动即失败;部分可选 Composio 配置(如 Slack、Gmail)在 Fixture 内用pytest.skip/pytest.fail明确区分"跳过"与"失败"。 - 并行竞争:多个 pytest-xdist worker 同时创建同名资源会触发唯一键冲突,conftest 中的 get-or-create 重试、独立 postb.in bin、独立测试 Collection 命名(时间戳 + uuid)共同降低了这类竞态;
rate_limit用例被强制排到最后也避免了配额竞争。 - 异步事件循环:E2E 目录的 pytest.ini 必须保留
asyncio_mode = auto与asyncio_default_fixture_loop_scope = function,否则异步 Fixture 与用例混跑会出现事件循环错位。
总而言之,Airweave 的后端测试体系以 backend/tests/README.md 为入口、以 backend/tests/e2e/config.py 的类型安全配置为底座、以 backend/tests/e2e/conftest.py 的多档位 Fixture 为骨架,配合标记调度与智能排序,构成了一套可本地调试、可并行、可上 CI 的真实环境冒烟测试方案——这也是理解 Airweave 后端各 API 与同步/搜索/限流机制最直接的入口。
【免费下载链接】airweaveOpen-source context retrieval layer for AI agents项目地址: https://gitcode.com/GitHub_Trending/ai/airweave
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考