AI Read API(mcp-api)— テストケース
このページは guinness-ai-v2 の apps/mcp-api/ のテスト計画である。io-definition.md のすべての行 — エンドポイント、クエリパラメータ、DocumentDB オペレーション、エラークラス — は、ここで少なくとも 1 つのテストケースにトレースされなければならない。コントラクト条項にテストがない場合、それが最優先で修正すべきバグである。
規約. テスト ID は
AM-<layer>-<NN>に従う。レイヤー:U(ユニット、I/O なし)、C(integration、実際の DocumentDB testcontainer、モック認証)、E(E2E、実際のクラウド)。各ケースは Given / When / Then を明示する。
テストレイヤーとツール
| レイヤー | スコープ | ツール |
|---|---|---|
| Unit (U) | 純粋関数: 認証検証、クエリパラメータパース、DocumentDB フィルタビルダー、レスポンスビルダー | pytest、ネットワークなし。DocumentDB / httpx は境界でモック |
| Integration (C) | 実際の testcontainer Mongo(DocumentDB API 互換 mongo:7 イメージ)+ デフォルトで有効なトークンを使用する完全リクエストライフサイクル |
pytest、testcontainers[mongodb]、httpx TestClient。Docker が必要 |
| End-to-end (E) | 実際の MCP Server → AI Read API → DocumentDB ラウンドトリップ(dev 環境) | 手動 / スモークのみ |
共有フィクスチャ
| フィクスチャ | 提供するもの | 使用テスト |
|---|---|---|
valid_token |
テスト用の AI_SERVICE_TOKEN の値 |
U, C |
design_doc(**overrides) |
整形された DocumentDB design ドキュメント |
U, C |
code_doc(**overrides) |
_id、name、source_code、visual.metadata.image_url を持つ整形された DocumentDB code ドキュメント |
U, C |
seed_design(collection, doc) |
design ドキュメントを testcontainer Mongo に挿入 | C |
seed_design_batch(collection, count, project_id) |
指定された project_id で N 件の design ドキュメントを挿入 |
C |
seed_code_batch(collection, count, project_id) |
指定された project_id で N 件の code ドキュメントを挿入 |
C |
カバレッジマトリックス
| ハッピーパス | 失敗パス | 冪等性 | |
|---|---|---|---|
| 認証(トークン) | AM-U-01 | AM-U-02, AM-U-03 | — |
| パラメータバリデーション | AM-U-04 | AM-U-05 | — |
GET /internal/designs/{design_id} |
AM-U-06, AM-C-01 | AM-C-02 | AM-C-05 |
GET /internal/designs |
AM-U-07, AM-C-03 | — | AM-C-05 |
GET /internal/code |
AM-U-08, AM-C-04 | — | AM-C-05 |
GET /internal/code/{code_id} |
AM-U-09, AM-C-06 | AM-C-07 | AM-C-05 |
| ページネーション (limit/offset) | AM-U-10 | — | — |
| 無効な limit(負の値 / 非整数) | AM-U-11 | — | — |
| 空の list 結果 | AM-C-08 | — | — |
| DocumentDB エラー | — | AM-C-09 | — |
ユニット (U) テスト
ネットワークなし。純粋な Python。
AM-U-01 — 有効な X-AI-Service-Token が受理
- Given 設定された環境変数値に一致する
X-AI-Service-Tokenを持つリクエスト。 - When 認証ミドルウェアがトークンを検証。
- Then 検証が通過(401 がスローされない)。
AM-U-02 — X-AI-Service-Token なし → 401
- Given
X-AI-Service-Tokenヘッダーのないリクエスト。 - When 認証ミドルウェアが検証。
- Then HTTP 401、
{ ok: false, error: { code: "UNAUTHORIZED" } }。
AM-U-03 — 誤ったトークン → 401
- Given 環境変数値に一致しない
X-AI-Service-Tokenを持つリクエスト。 - When 認証ミドルウェアが検証。
- Then HTTP 401、
{ ok: false, error: { code: "UNAUTHORIZED" } }。 - And 比較がタイミングセーフ(実装が
hmac.compare_digestまたは同等を使用していることを検証 — ショートサーキットなし)。
AM-U-04 — path で route を選択
- Given
/internal/designs,/internal/designs/{design_id},/internal/code,/internal/code/{code_id}。 - When ルータが handler を決定。
- Then list-designs, get-design-detail, list-code, get-code-detail をそれぞれ選択する。
AM-U-05 — list endpoint に project_id がない → 400
- Given
project_idなしのGET /internal/designsまたはGET /internal/code。 - When ルータがパラメータを検証。
- Then HTTP 400、
{ ok: false, error: { code: "BAD_REQUEST" } }。
AM-U-06 — design_id クエリが正しい DocumentDB フィルタを構築
- Given
design_id = "1_abc_def"。 - When リポジトリがクエリを構築。
- Then フィルタは
{"_id": "1_abc_def"}。 - And オペレーションは
find_one(findではない)。
AM-U-07 — list-designs がプロジェクション付きの正しいフィルタを構築
- Given
project_id = 42、organization_id = 1、limit = 10、offset = 5。 - When リポジトリが design list query を構築。
- Then フィルタは
{"project_id": 42, "organization_id": 1}。 - And projection はすべての
vector_embeddingfield を除外する。 - And カーソルに
.skip(5).limit(10)がある。
AM-U-08 — list-code がプロジェクション付きの正しいフィルタを構築
- Given
project_id = 42、organization_id = 1、limit = 10、offset = 5。 - When リポジトリが code list query を構築。
- Then フィルタは
{"project_id": 42}。 - And projection は
_id,organization_id,project_id,name,type,based_on,visual.metadata.image_urlを含む。 - And
source_code,css_code, すべてのvector_embeddingfield を除外する。 - And カーソルに
.skip(5).limit(10)がある。
AM-U-09 — code detail が正しい DocumentDB filter を構築
- Given
code_id = "660e8400-e29b-41d4-a716-446655440001"。 - When リポジトリが query を構築。
- Then filter は
{"_id": "660e8400-e29b-41d4-a716-446655440001"}。 - And operation は
find_one。 - And projection はすべての
vector_embeddingfield を除外する。
AM-U-10 — limit/offset が正しく適用される
- パラメータ化:
limitなし → デフォルト 20。limit = 200→ 100 にキャップ。offsetなし → デフォルト 0。offset = 50→.skip(50)。- Then 正しい値が DocumentDB カーソルに渡される。
AM-U-11 — 無効な limit はデフォルトにフォールバック
- パラメータ化:
limit = -1→ デフォルト 20 にフォールバック。limit = 0→ デフォルト 20 にフォールバック。limit = "abc"(非整数文字列)→ デフォルト 20 にフォールバック。- Then DocumentDB カーソルに
.limit(20)が渡される。 - And エラーは返されない — 無効な値は I/O コントラクトに従い暗黙に修正される。
AM-U-12 — offset が合計件数を超過 → 空のページ
- Given
project_id = 42でcodeコレクションに 5 件のドキュメントがある。 - When
GET /internal/code?project_id=42&offset=100。 - Then HTTP 200。
{ ok: true, data: { project_id: 42, total: 5, items: [] } }。- And
totalは実際の件数(5)を反映し、0 ではない。
Integration (C) テスト
実際の testcontainer Mongo(DocumentDB API 互換)。認証はモック(デフォルトで有効なトークン)。
AM-C-01 — design_id で GET — ドキュメントが見つかる
- Given:
designコレクションに_id = "1_abc_def"、project_id = 42、name = "Login Screen"、visual.metadata.image_url = "s3://..."のドキュメントがある。- 有効な認証トークン。
- When
GET /internal/designs/1_abc_def。 - Then:
- HTTP 200。
{ ok: true, data: { id: "1_abc_def", project_id: 42, name: "Login Screen", image_url: "s3://..." } }。dataにvector_embeddingやその他の内部フィールドが含まれていない。
AM-C-02 — design_id で GET — ドキュメントが見つからない
- Given:
designコレクションに_id = "nonexistent"のドキュメントがない。- 有効な認証トークン。
- When
GET /internal/designs/nonexistent。 - Then:
- HTTP 404。
{ ok: false, data: null, error: { code: "NOT_FOUND", message: "Design not found" } }。
AM-C-03 — project_id で design list
- Given:
designコレクションにproject_id = 42のドキュメントが 25 件ある。- 有効な認証トークン。
- When
GET /internal/designs?project_id=42&limit=10&offset=5。 - Then:
- HTTP 200。
{ ok: true, data: { project_id: 42, total: 25, items: [...] } }。vector_embeddingフィールドの漏洩がない。
AM-C-04 — project_id で code list
- Given:
codeコレクションにproject_id = 42のドキュメントが 25 件ある。- 有効な認証トークン。
- When
GET /internal/code?project_id=42&organization_id=1&limit=10&offset=5。 - Then:
- HTTP 200。
{ ok: true, data: { project_id: 42, total: 25, items: [...] } }。items配列が正確に 10 アイテム。- 各 code item に
id,project_id,organization_id,name,image_urlがある。 - code list item は
source_code/css_codeを含まない。 vector_embeddingフィールドの漏洩がない。
AM-C-05 — 同一リクエストの繰り返しが同じデータを返す
- Given AM-C-01 のセットアップ(design が見つかる)。
- When 同じ
GET /internal/designs/1_abc_defが 2 回呼び出される。 - Then 両方のレスポンスが同一(ステートレス、冪等)。
AM-C-06 — code detail が見つかる
- Given
codeコレクションに_id = "660e8400-e29b-41d4-a716-446655440001"のドキュメントがある。 - When
GET /internal/code/660e8400-e29b-41d4-a716-446655440001。 - Then HTTP 200。
data.codeはsource_codeを含み、vector_embeddingを含まない。
AM-C-07 — code detail が見つからない
- Given
_id = "missing"の code document がない。 - When
GET /internal/code/missing。 - Then HTTP 404、
{ ok: false, data: null, error: { code: "NOT_FOUND" } }。
AM-C-08 — list endpoint のコレクションが空
- Given:
codeコレクションにproject_id = 99のドキュメントがない。- 有効な認証トークン。
- When
GET /internal/code?project_id=99&organization_id=1。 - Then:
- HTTP 200(404 ではない — 空の結果はエラーではない)。
{ ok: true, data: { project_id: 99, total: 0, items: [] } }。
AM-C-09 — DocumentDB 接続エラー
- Given:
- Mongo testcontainer が停止 / 一時停止(接続失敗をシミュレート)。
- 有効な認証トークン。
- When
GET /internal/designs/1_abc_def。 - Then:
- HTTP 500。
{ ok: false, data: null, error: { code: "INTERNAL_ERROR", message: "..." } }。- ERROR レベルでエラーがログに記録される(
ai-mcp.query.failed)。
E2E (E) テスト
スモークテストセット。実際のサービスに対して手動で実行。
AM-E-01 — MCP Server → AI Read API ラウンドトリップ
- Given 実際の
AI_SERVICE_URLとAI_SERVICE_TOKENで dev に対して設定された MCP Server。 - When MCP クライアントが既知の ID で
list-designs,list-code,get-design-detail,get-code-detailを呼び出す。 - Then 30 秒以内に:
- MCP レスポンスに DocumentDB のdesign/code dataが含まれる。
- CloudWatch に表示:
ai-mcp.request.received→ai-mcp.query.completed→ai-mcp.response.sent。 - 401 または 500 エラーがない。
横断チェック
該当するテスト全体で成立すべき条件。独立したテスト行ではなく、上記のテストのレビュー時や実行時に検証する。
- Postgres 接続が開かれない。 Postgres ドライバに到達できない状態(またはガード環境変数を設定)でテストを実行。誤ったドライバインポートが即座に表面化。
- レスポンスが常に
{ ok, data, error }エンベロープに従う。 全テストでエンベロープ構造を表明 — エラーレスポンスも準拠する必要がある。 - 認証がタイミングセーフ。 実装が
hmac.compare_digestまたは同等を使用していることを検証 — シークレット文字列に==を使用しない。 - 全テストで DocumentDB 書き込みがない。 各テストの前後で
collection.count_documents()が変更されていないことを表明。 vector_embeddingフィールドの漏洩がない。 レスポンスデータを表明する全テストで、出力にvector_embeddingキーが含まれていないことを検証。- detail route は
totalやitems配列を返さない。 list route は page list、detail route は{ design: ... }または{ code: ... }を返す。 - エラーレスポンスに
dataが含まれない。ok = falseの場合、dataはnullでなければならない(省略でも空オブジェクトでもなく)。
意図的なスコープ外
将来のテストが正しいバケットに配置されるよう、明示的に列挙。
- MCP Server の認証とツールルーティング。
mcp/テストケース設計が管轄。この API は独自のX-AI-Service-Tokenのみを検証。 - DocumentDB インデックス管理。
packages/models/が管轄。この API はインデックスが存在することを前提とする。 - SQS とのやり取り。 この API は HTTP のみ。SQS は関与しない。
- CORS / CloudFront 設定。 インフラレベル。この API は VPC 内部のみ。
- レートリミット / スロットリング。 TBD。仕様化されるまでテストなし。
- generated-code endpoint。 将来の endpoint。まだ contract にない。
- データ移行またはシード。 運用上の懸念。テストフィクスチャは独自のデータを管理。