# 帳票設計書 7-v8-serializer

## 概要

本ドキュメントは、Node.jsテストランナーの「V8シリアライザーレポーター」の設計仕様を記載したものである。テスト結果をV8シリアライズ形式（バイナリ）で出力するレポーター機能の実装詳細、出力形式、処理フローについて説明する。

### 本帳票の処理概要

V8シリアライザーレポーターは、Node.jsテストランナーが実行したテスト結果を、V8エンジンのシリアライズ形式（バイナリ）で標準出力に出力する帳票である。プロセス間通信（IPC）でのテスト結果受け渡しに使用され、子プロセスから親プロセスへのテスト結果転送に最適化されている。

**業務上の目的・背景**：Node.jsテストランナーは、テストの分離実行のために子プロセスでテストを実行することがある。子プロセスから親プロセスへテスト結果を効率的に転送するため、V8のネイティブシリアライズ機能を使用したバイナリフォーマットが必要である。テキストベースのフォーマット（TAP等）と比較して、構造化データの正確な転送と高速なパース処理が可能になる。

**帳票の利用シーン**：
- NODE_TEST_CONTEXT=child-v8での子プロセステスト実行
- プロセス間でのテスト結果転送
- 複雑なエラーオブジェクトの完全なシリアライズ
- 高速なテスト結果処理が必要な場合

**主要な出力内容**：
1. V8シリアライズヘッダー
2. メッセージ長プレフィックス（4バイト、ビッグエンディアン）
3. シリアライズされたテストイベントデータ
4. エラーオブジェクトのシリアライズ形式変換

**帳票の出力タイミング**：
- 各テストイベント発生時にリアルタイムで出力
- 子プロセスでのテスト実行時に自動選択

**帳票の利用者**：
- Node.jsテストランナー内部（親プロセス）
- プロセス間通信を使用するテストフレームワーク

## 帳票種別

テストレポート / バイナリ形式（V8シリアライズ）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | 子プロセス | NODE_TEST_CONTEXT=child-v8 | 自動選択 |
| - | CLIターミナル | - | 内部使用のみ |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | バイナリ（V8シリアライズ） |
| 用紙サイズ | N/A（バイナリ出力） |
| 向き | N/A |
| ファイル名 | N/A（標準出力へ直接出力） |
| 出力方法 | 標準出力（stdout） |
| 文字コード | バイナリ（エンディアン依存） |

### V8シリアライズ固有設定

| 項目 | 内容 |
|-----|------|
| シリアライザー | v8.DefaultSerializer |
| メッセージ長 | 4バイト、ビッグエンディアン |
| エラー変換 | serializeError関数で変換 |

## 帳票レイアウト

### レイアウト概要

V8シリアライザーレポーターは、各メッセージを以下の構造でバイナリ出力する。

```
┌─────────────────────────────────────┐
│          V8ヘッダー                  │
│  [V8 serialization header bytes]   │
├─────────────────────────────────────┤
│          メッセージ長（4バイト）      │
│  [length >> 24 & 0xFF]             │
│  [length >> 16 & 0xFF]             │
│  [length >> 8 & 0xFF]              │
│  [length & 0xFF]                   │
├─────────────────────────────────────┤
│          V8ヘッダー（2回目）         │
│  [V8 serialization header bytes]   │
├─────────────────────────────────────┤
│          シリアライズデータ          │
│  [serialized event data]           │
└─────────────────────────────────────┘
```

### メッセージ構造

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | V8ヘッダー | シリアライズヘッダー | writeHeader() | バイナリ |
| 2 | 長さプレフィックス | メッセージ長（4バイト） | Buffer.allocUnsafe(4) | ビッグエンディアン |
| 3 | 内部V8ヘッダー | 値用ヘッダー | writeHeader() | バイナリ |
| 4 | シリアライズ値 | イベントデータ | writeValue(item) | バイナリ |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 全イベント | すべてのテストイベントを処理 | Yes |
| NODE_TEST_CONTEXT | child-v8の場合に自動選択 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | イベント発生順 | 昇順（時系列） |

### 改ページ条件

なし（連続バイナリストリーム）

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

### 参照テーブル一覧

本帳票はデータベースを参照しない。テストランナーからのイベントストリームを入力として使用する。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | - | - |

### イベントデータ構造

#### 全テストイベント

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| item | シリアライズ対象 | - | 全イベントをそのまま処理 |
| item.data.details.error | エラーオブジェクト | エラーがある場合 | serializeErrorで変換 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ヘッダー長 | TypedArrayPrototypeGetLength(serializer.releaseBuffer()) | N/A | 初回ヘッダーで測定 |
| メッセージ長 | serializedMessage.length - (4 + headerLength) | N/A | 本体のみの長さ |
| 長さバイト0 | serializedMessageLength >> 24 & 0xFF | N/A | ビッグエンディアン |
| 長さバイト1 | serializedMessageLength >> 16 & 0xFF | N/A | ビッグエンディアン |
| 長さバイト2 | serializedMessageLength >> 8 & 0xFF | N/A | ビッグエンディアン |
| 長さバイト3 | serializedMessageLength & 0xFF | N/A | ビッグエンディアン |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[レポーター初期化] --> B[DefaultSerializer作成]
    B --> C[ヘッダー出力・長さ測定]
    C --> D[イベント待機]
    D --> E[イベント受信]
    E --> F{エラーあり?}
    F -->|Yes| G[serializeError変換]
    F -->|No| H[ヘッダー出力]
    G --> H
    H --> I[4バイト長さ領域確保]
    I --> J[ヘッダー出力（2回目）]
    J --> K[writeValue(item)]
    K --> L{エラー変換した?}
    L -->|Yes| M[元のエラーに復元]
    L -->|No| N[バッファ取得]
    M --> N
    N --> O[メッセージ長計算]
    O --> P[長さバイト設定]
    P --> Q[yieldでバイナリ出力]
    Q --> D
```

### serializeError処理

```mermaid
flowchart TD
    A[エラーオブジェクト] --> B[serializeError関数呼び出し]
    B --> C[シリアライズ可能形式に変換]
    C --> D[変換結果をitem.data.details.errorに設定]
    D --> E[シリアライズ実行]
    E --> F[元のエラーに復元]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| シリアライズエラー | V8でシリアライズ不可能なオブジェクト | - | serializeErrorで事前変換 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 無制限（ストリーム処理） |
| 目標出力時間 | イベント受信後即時出力 |
| 同時出力数上限 | 1（シングルストリーム） |

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

- バイナリ形式のため、人間には可読でない
- エラーオブジェクトに含まれる機密情報がシリアライズされる可能性がある
- 信頼できないソースからのデシリアライズは避けるべき（RCE脆弱性の可能性）

## 備考

- 非同期ジェネレータ関数として実装
- NODE_TEST_CONTEXT=child-v8の場合にkBuiltinReportersに動的登録
- エラーオブジェクトは一時的にシリアライズ形式に変換され、出力後に復元される
- メッセージ長はビッグエンディアンで4バイトプレフィックスとして付加
- v8.DefaultSerializerを使用して効率的なバイナリシリアライズを実現

---

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

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

### 推奨読解順序

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

V8シリアライズの基本構造とメッセージフォーマットを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | v8-serializer.js | `lib/internal/test_runner/reporter/v8-serializer.js` | メッセージ構造とヘッダー長計算 |
| 1-2 | error_serdes.js | `lib/internal/error_serdes.js` | serializeError関数の実装 |

**読解のコツ**: V8のDefaultSerializerは内部的にヘッダーを出力するため、ヘッダー長を最初に測定してメッセージ長計算に使用する。

#### Step 2: エントリーポイントを理解する

v8Reporter非同期ジェネレータ関数の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | v8-serializer.js | `lib/internal/test_runner/reporter/v8-serializer.js` | v8Reporter関数全体（11-45行目） |

**主要処理フロー**:
1. **12行目**: DefaultSerializerインスタンス作成
2. **13-14行目**: ヘッダー出力・長さ測定
3. **16-43行目**: イベントループ
4. **17-23行目**: エラーオブジェクトのシリアライズ変換
5. **24-28行目**: ヘッダー + 長さ領域 + ヘッダー + 値をシリアライズ
6. **30-32行目**: 元のエラーに復元
7. **34-42行目**: メッセージ長計算と長さバイト設定
8. **43行目**: yieldでバイナリ出力

#### Step 3: メッセージ長計算を理解する

4バイトのビッグエンディアン長さプレフィックスの設定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | v8-serializer.js | `lib/internal/test_runner/reporter/v8-serializer.js` | 長さ計算と設定（34-42行目） |

**主要処理フロー**:
- **35行目**: メッセージ長 = バッファ長 - (4 + ヘッダー長)
- **37-41行目**: ビッグエンディアンで4バイト設定
- **42行目**: serializedMessage.setでバイト書き込み

#### Step 4: エラーシリアライズを理解する

serializeError関数によるエラーオブジェクトの変換を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | v8-serializer.js | `lib/internal/test_runner/reporter/v8-serializer.js` | エラー変換処理（17-23, 30-32行目） |
| 4-2 | error_serdes.js | `lib/internal/error_serdes.js` | serializeError関数の詳細 |

**主要処理フロー**:
- **17行目**: originalErrorを保存
- **22行目**: serializeError()で変換
- **30-32行目**: 元のエラーに復元

#### Step 5: 動的レポーター登録を理解する

NODE_TEST_CONTEXT=child-v8での動的登録を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | utils.js | `lib/internal/test_runner/utils.js` | 動的登録（238-241行目） |

**主要処理フロー**:
- **238行目**: `isChildProcessV8`の判定
- **239行目**: kBuiltinReportersに'v8-serializer'を追加
- **240行目**: reporters配列に'v8-serializer'を設定

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

```
NODE_TEST_CONTEXT=child-v8 node --test
    │
    ├─ lib/internal/test_runner/utils.js
    │      └─ parseCommandLine()
    │             └─ isChildProcessV8判定 → kBuiltinReportersに動的登録
    │
    └─ lib/internal/test_runner/reporter/v8-serializer.js
           │
           ├─ v8Reporter (async generator)
           │      ├─ DefaultSerializer
           │      │      ├─ writeHeader()
           │      │      ├─ writeRawBytes()
           │      │      ├─ writeValue()
           │      │      └─ releaseBuffer()
           │      │
           │      └─ serializeError()
           │             └─ lib/internal/error_serdes.js
           │
           └─ Buffer.allocUnsafe()
                  └─ buffer
```

### データフロー図

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

テストイベント ───▶ v8Reporter ジェネレータ ───▶ 標準出力(stdout)
  ストリーム              │                           [バイナリ]
                         │
                         ├─ エラー変換
                         │     └─ serializeError()
                         │
                         ├─ シリアライズ
                         │     ├─ writeHeader()
                         │     ├─ 4バイト長さ領域
                         │     ├─ writeHeader()
                         │     └─ writeValue(item)
                         │
                         ├─ 長さ計算・設定
                         │     └─ ビッグエンディアン4バイト
                         │
                         └─ yield serializedMessage
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| v8-serializer.js | `lib/internal/test_runner/reporter/v8-serializer.js` | ソース | V8シリアライザーレポーターのメイン実装 |
| error_serdes.js | `lib/internal/error_serdes.js` | ソース | serializeError関数 |
| utils.js | `lib/internal/test_runner/utils.js` | ソース | 動的レポーター登録 |
| v8.js | `v8` | Node.js組込み | DefaultSerializer |
| buffer.js | `buffer` | Node.js組込み | Buffer.allocUnsafe |
| runner.js | `lib/internal/test_runner/runner.js` | ソース | テストランナーのメイン処理 |
