# 帳票設計書 4-Test Results Storage

## 概要

本ドキュメントは、VS Codeのテストランナーで実行されたテスト結果をJSON形式で永続化するTest Results Storage機能の帳票出力仕様を定義するものである。

### 本帳票の処理概要

Test Results Storageは、テストエクスプローラーで実行されたテスト結果を自動的にワークスペースストレージに保存し、VS Code再起動後も結果を参照できるようにする機能である。

**業務上の目的・背景**：テスト実行結果の永続化により、VS Code再起動後もテスト結果を確認可能にする。開発者がテストのデグレッションを追跡し、過去のテスト結果と比較するための基礎データを提供する。

**帳票の利用シーン**：テストエクスプローラーでテストを実行した際に自動的にバックグラウンドで保存される。ユーザーが明示的に操作する必要はなく、システムが自動的に管理する。

**主要な出力内容**：
1. テスト実行ID
2. テストケースの階層構造
3. 各テストケースの実行結果（pass/fail/skip等）
4. 実行時間
5. エラーメッセージ
6. テスト出力

**帳票の出力タイミング**：テスト実行完了時に自動保存。

**帳票の利用者**：VS Code内部（テストエクスプローラー）、間接的に開発者

## 帳票種別

内部データストレージ / 自動保存

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Test Explorer | workbench.view.testing | テスト実行時に自動保存 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | `{resultId}.json` |
| 出力方法 | ワークスペースストレージへの自動書き込み |
| 文字コード | UTF-8 |

### 出力制限

| 項目 | 内容 |
|-----|------|
| 最大保持件数 | 128件（RETAIN_MAX_RESULTS） |
| 最小保持件数 | 16件（RETAIN_MIN_RESULTS） |
| 最大保持バイト数 | 128KB（RETAIN_MAX_BYTES） |
| クリーンアップ確率 | 20%（CLEANUP_PROBABILITY） |

### 保存先

| 項目 | 内容 |
|-----|------|
| ディレクトリ | `{workspaceStorageHome}/{workspaceId}/testResults/` |
| 結果ファイル | `{resultId}.json` |
| 出力ファイル | `{resultId}.output` |

## 帳票レイアウト

### レイアウト概要

ISerializedTestResults interface に基づくJSONオブジェクト。

```json
{
  "id": "...",
  "completedAt": 1234567890,
  "items": [
    {
      "item": { "extId": "...", "label": "..." },
      "tasks": [
        {
          "state": 2,
          "duration": 100,
          "messages": []
        }
      ],
      "children": []
    }
  ]
}
```

### ルートオブジェクト

| No | 項目名 | 説明 | データ型 | 必須 |
|----|-------|------|---------|------|
| 1 | id | テスト結果の一意識別子 | string | Yes |
| 2 | completedAt | 完了時刻（Unix timestamp） | number | Yes |
| 3 | items | テスト項目配列 | ISerializedTestResultItem[] | Yes |

### items オブジェクト

| No | 項目名 | 説明 | データ型 | 備考 |
|----|-------|------|---------|------|
| 1 | item | テスト項目情報 | ITestItem | テスト定義 |
| 2 | tasks | タスク結果配列 | ISerializedTaskState[] | 実行結果 |
| 3 | children | 子テスト項目のextId | string[] | 階層構造 |
| 4 | parent | 親テストextId | string | optional |
| 5 | retired | 無効化フラグ | boolean | optional |
| 6 | expand | 展開状態 | TestItemExpandState | optional |

### tasks オブジェクト

| No | 項目名 | 説明 | データ型 | 備考 |
|----|-------|------|---------|------|
| 1 | state | テスト状態 | TestResultState | enum値 |
| 2 | duration | 実行時間(ms) | number | optional |
| 3 | messages | エラー/出力メッセージ | ITestMessage[] | 配列 |

### TestResultState enum

| 値 | 名前 | 説明 |
|----|------|------|
| 0 | Unset | 未設定 |
| 1 | Queued | キュー待ち |
| 2 | Running | 実行中 |
| 3 | Passed | 成功 |
| 4 | Failed | 失敗 |
| 5 | Skipped | スキップ |
| 6 | Errored | エラー |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| テスト完了 | テストランの完了 | Yes |
| 結果存在 | 空でない結果が存在 | Yes |

### 保持条件

テスト結果は以下の条件に基づいて保持・削除される：

1. 最大128件まで保持
2. 最小16件は常に保持（バイト制限を超えても）
3. 合計サイズが128KBを超える場合、古い結果から削除
4. データリビジョンが異なる結果は自動削除

### クリーンアップ条件

| 条件名 | 説明 |
|-------|------|
| 確率トリガー | persist()呼び出し時に20%の確率で実行 |
| 孤児ファイル削除 | stored配列に含まれないファイルを削除 |
| リビジョンチェック | currentRevision !== rec.revの結果を削除 |

### 改ページ条件

N/A（JSONファイル出力のため改ページなし）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| StorageService (storedTestResults) | 結果メタデータ | StorageScope.WORKSPACE |

### データ取得元

#### ITestResult

| 参照項目 | 帳票項目との対応 | 取得方法 | 備考 |
|---------|----------------|---------|------|
| id | id | ITestResult | 結果ID |
| completedAt | completedAt | ITestResult | 完了時刻 |
| toJSON() | items | ITestResult | シリアライズ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| バイト数 | VSBuffer.fromString(JSON.stringify(obj)).byteLength | - | 制限チェック用 |
| バジェット | RETAIN_MAX_BYTES - 累積バイト数 | - | 残り容量 |

## 処理フロー

### 保存フロー

```mermaid
flowchart TD
    A[テスト実行完了] --> B[ITestResult.toJSON]
    B --> C[persist呼び出し]
    C --> D{既存結果?}
    D -->|Yes| E[既存バイト数を引き継ぎ]
    D -->|No| F[新規保存処理]
    E --> G{バジェット確認}
    F --> G
    G -->|超過| H{最小件数確保?}
    H -->|Yes| I[古い結果削除]
    H -->|No| J[そのまま追加]
    I --> J
    J --> K[storeForResultId]
    K --> L[stored配列更新]
    L --> M{クリーンアップ実行?}
    M -->|20%確率| N[cleanupDereferenced]
    M -->|80%確率| O[完了]
    N --> O
```

### 読み込みフロー

```mermaid
flowchart TD
    A[VS Code起動] --> B[read呼び出し]
    B --> C[stored配列取得]
    C --> D{各レコード処理}
    D --> E{リビジョン一致?}
    E -->|No| F[スキップ]
    E -->|Yes| G[readForResultId]
    G --> H{読み込み成功?}
    H -->|No| F
    H -->|Yes| I[HydratedTestResult生成]
    F --> D
    I --> D
    D -->|完了| J[有効な結果のみ返却]
    J --> K[stored配列更新]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| デシリアライズエラー | JSONパース失敗 | warn log出力 | 該当結果をスキップ |
| ファイル読み込みエラー | ファイルが存在しない | - | undefinedを返却 |
| ファイル書き込みエラー | ディスク書き込み失敗 | - | 例外をそのまま伝播 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 最大128件の結果 |
| 目標保存時間 | 100ms以内 |
| 目標読み込み時間 | 500ms以内 |

## セキュリティ考慮事項

- テスト結果はローカルワークスペースストレージに保存
- 機密情報（環境変数、パス等）がテスト出力に含まれる可能性
- ストレージはユーザー権限でのみアクセス可能
- リモートワークスペースではリモートストレージを使用

## 備考

- データリビジョン（currentRevision = 1）の変更時は過去データが破棄される
- InMemoryResultStorageはテスト用で本番では使用されない
- output ファイルはストリーム形式で別途保存される

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

テスト結果のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | testTypes.ts | `src/vs/workbench/contrib/testing/common/testTypes.ts` | ISerializedTestResults, TestResultState enum |
| 1-2 | testResult.ts | `src/vs/workbench/contrib/testing/common/testResult.ts` | ITestResult interface, HydratedTestResult class |

**読解のコツ**: TestResultStateのenum値（0-6）が各テスト状態を表す。

#### Step 2: ストレージサービスを理解する

永続化の仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | testResultStorage.ts | `src/vs/workbench/contrib/testing/common/testResultStorage.ts` | ITestResultStorage interface (行26-38) |
| 2-2 | testResultStorage.ts | `src/vs/workbench/contrib/testing/common/testResultStorage.ts` | 定数定義 (行21-24) |
| 2-3 | testResultStorage.ts | `src/vs/workbench/contrib/testing/common/testResultStorage.ts` | BaseTestResultStorage (行49-181) |

**主要処理フロー**:
- **行21-24**: 保持制限の定数定義
- **行52**: StoredValue（メタデータ保存）
- **行70-95**: read() - 結果の読み込み
- **行109-150**: persist() - 結果の保存

#### Step 3: ファイルベース実装を理解する

実際のファイル操作を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | testResultStorage.ts | `src/vs/workbench/contrib/testing/common/testResultStorage.ts` | TestResultStorage (行213-300) |

**主要処理フロー**:
- **行225**: ディレクトリパスの構築
- **行228-230**: readForResultId() - JSON読み込み
- **行233-234**: storeForResultId() - JSON書き込み
- **行267-272**: persist() override（クリーンアップ実行）
- **行278-291**: cleanupDereferenced() - 孤児ファイル削除

### プログラム呼び出し階層図

```
テスト実行完了
    │
    └─ TestResultService.push()
           │
           └─ TestResultStorage.persist()
                  │
                  ├─ stored.get() // メタデータ取得
                  │
                  ├─ for each result:
                  │      │
                  │      ├─ 既存チェック
                  │      │
                  │      ├─ バジェットチェック
                  │      │
                  │      └─ storeForResultId()
                  │             │
                  │             └─ fileService.writeFile()
                  │
                  ├─ 削除対象の deleteForResultId()
                  │
                  ├─ stored.store() // メタデータ更新
                  │
                  └─ cleanupDereferenced() (20%確率)
                         │
                         └─ fileService.resolve()
                                │
                                └─ fileService.del() (孤児ファイル)
```

### データフロー図

```
[入力]                    [処理]                           [出力]

ITestResult[]        ┌─────────────────────┐
                     │                     │
  ─────────────────▶│  TestResultStorage  │
                     │                     │
                     │ - persist()         │
                     │   - バジェット計算   │──────▶ {id}.json
                     │   - 古い結果削除     │         (結果データ)
                     │   - storeForResultId │
                     │   - cleanupDeref    │──────▶ {id}.output
                     │                     │         (出力データ)
                     └─────────────────────┘
                            │
                            ▼
                     StorageService
                     (storedTestResults key)
                            │
                            ▼
                     メタデータ配列
                     [{rev, id, bytes}]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| testResultStorage.ts | `src/vs/workbench/contrib/testing/common/testResultStorage.ts` | ソース | ストレージ実装 |
| testResult.ts | `src/vs/workbench/contrib/testing/common/testResult.ts` | ソース | テスト結果モデル |
| testTypes.ts | `src/vs/workbench/contrib/testing/common/testTypes.ts` | ソース | 型定義 |
| storedValue.ts | `src/vs/workbench/contrib/testing/common/storedValue.ts` | ソース | ストレージ値ユーティリティ |
| testResultService.ts | `src/vs/workbench/contrib/testing/common/testResultService.ts` | ソース | テスト結果サービス |
