Files
cobol-java-v3/docs/output-directory-structure.md
T
hangshuo652 bdc1584b3c feat: 修复 Java Runner command_line 参数传递 + DB-Java 比对功能
- 修复 orchestrator_db.py: Java Runner 未传递 command_line 参数导致 ABEND
- 新增 DB-Java 文件式运行 + DB 表比对功能
- 优化输出目录结构: output/<PROGRAM_ID>/cobol/
- 新增测试文件: test_java_comparison.py, test_java_e2e.py
- 更新 AI 使用日志
2026-09-09 21:35:21 +08:00

401 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# V3系统目录结构设计文档
## 一、目录结构概述
V3系统采用统一的目录结构来组织COBOL和Java的输出结果,确保所有程序的输出文件都位于同一个根目录下,便于管理和比较。
## 二、目录结构规范
### 2.1 标准目录结构
```
output/<PROGRAM_ID>/
├── cobol/ # COBOL输出(所有组)
│ ├── main/ # 单轮/默认场景
│ │ ├── input/ # COBOL输入flat文件
│ │ ├── output/ # COBOL输出flat文件
│ │ └── json/ # Java验证用JSON
│ ├── run_skip/ # 跳过场景
│ │ ├── input/
│ │ ├── output/
│ │ └── json/
│ ├── run_<scenario_id>/ # 多轮场景
│ │ ├── input/
│ │ ├── output/
│ │ └── json/
│ └── pre_src/ # 预处理源码
├── java/ # Java输出(所有组)
│ ├── main/ # 对应cobol/main的Java输出
│ │ └── output/
│ ├── run_skip/ # 对应cobol/run_skip的Java输出
│ │ └── output/
│ └── run_<scenario_id>/ # 对应cobol/run_*的Java输出
│ └── output/
├── coverage/ # 覆盖率报告(全局)
├── logs/ # 日志(全局)
│ ├── main.log
│ ├── run_skip.log
│ └── run_<scenario_id>.log
├── gcov/ # gcov数据(按场景分离)
│ ├── run_main/
│ ├── run_skip/
│ └── run_<scenario_id>/
├── data/ # SQLite数据库(按场景分离)
│ ├── kin.db # 单轮场景
│ └── kin_<scenario_id>.db # 多轮场景
└── reports/ # 测试报告
└── <timestamp>/
├── result.json
├── report.html
└── machine.json
```
### 2.2 目录命名规则
| 目录 | 命名规则 | 说明 |
|------|----------|------|
| `cobol/main/` | 固定名称 | 单轮/默认场景 |
| `cobol/run_skip/` | 固定名称 | 跳过场景(原 `skip/` |
| `cobol/run_<id>/` | `run_` + 场景ID | 多轮场景 |
| `java/<对应cobol目录>/` | 与cobol目录对应 | Java输出 |
| `coverage/` | 固定名称 | 覆盖率报告 |
| `logs/` | 固定名称 | 日志文件 |
| `gcov/run_<id>/` | `run_` + 场景ID | gcov数据 |
| `data/` | 固定名称 | SQLite数据库 |
### 2.3 文件命名规则
| 文件类型 | 命名规则 | 示例 |
|----------|----------|------|
| COBOL输入文件 | `<PROGRAM_ID>R<NN>` | `KIN01R01`, `ZAN01R01` |
| COBOL输出文件 | `<PREFIX>W<NN>` | `KIN01W01`, `ZAN01W01` |
| JSON中介文件 | `<PROGRAM_ID>.json` | `KIN01INP.json` |
| 覆盖率报告 | `<PROGRAM_ID>_coverage.html` | `KIN01INP_coverage.html` |
| 运行日志 | `<场景ID>.log` | `main.log`, `run_normal.log` |
| gcov数据 | 按场景ID分目录 | `gcov/run_main/`, `gcov/run_skip/` |
| SQLite数据库 | `kin_<场景ID>.db` | `kin.db`, `kin_normal.db` |
## 三、场景映射规则
### 3.1 单轮场景
**定义**:程序只有一次执行,无多场景配置。
**目录结构**
```
output/<PROGRAM_ID>/
├── cobol/
│ └── main/
│ ├── input/
│ ├── output/
│ └── json/
├── java/
│ └── main/
│ └── output/
├── coverage/
├── logs/
│ └── main.log
├── gcov/
│ └── run_main/
└── data/
└── kin.db
```
### 3.2 多轮场景
**定义**:程序有多次执行,通过YAML配置文件定义场景。
**目录结构**
```
output/<PROGRAM_ID>/
├── cobol/
│ ├── run_normal/
│ │ ├── input/
│ │ ├── output/
│ │ └── json/
│ ├── run_insert_error/
│ │ ├── input/
│ │ ├── output/
│ │ └── json/
│ └── run_sql_delete_error/
│ ├── input/
│ ├── output/
│ └── json/
├── java/
│ ├── run_normal/
│ │ └── output/
│ ├── run_insert_error/
│ │ └── output/
│ └── run_sql_delete_error/
│ └── output/
├── coverage/
├── logs/
│ ├── run_normal.log
│ ├── run_insert_error.log
│ └── run_sql_delete_error.log
├── gcov/
│ ├── run_normal/
│ ├── run_insert_error/
│ └── run_sql_delete_error/
└── data/
├── kin_normal.db
├── kin_insert_error.db
└── kin_sql_delete_error.db
```
### 3.3 跳过场景
**定义**:程序有跳过主FD输入的场景(旧版 `skip/` 目录)。
**目录结构**
```
output/<PROGRAM_ID>/
├── cobol/
│ ├── main/
│ │ ├── input/
│ │ ├── output/
│ │ └── json/
│ └── run_skip/
│ ├── input/
│ ├── output/
│ └── json/
├── java/
│ ├── main/
│ │ └── output/
│ └── run_skip/
│ └── output/
├── coverage/
├── logs/
│ ├── main.log
│ └── run_skip.log
├── gcov/
│ ├── run_main/
│ └── run_skip/
└── data/
├── kin.db
└── kin_skip.db
```
## 四、路径依赖说明
### 4.1 env_overrides 路径
COBOL运行时通过环境变量映射文件路径:
```python
# 输入文件
env_overrides[fname] = os.path.join("input", fname)
# 输出文件
env_overrides[fname] = os.path.join("output", fname)
```
**注意**:这些是相对于CWD的路径,CWD为 `cobol/main/``cobol/run_<id>/`
### 4.2 SQLite数据库路径
```python
# 单轮场景
db_path = data/kin.db
# 多轮场景
db_path = data/kin_<scenario_id>.db
```
### 4.3 gcov数据路径
```python
# 单轮场景
gcov_dir = gcov/run_main/
# 多轮场景
gcov_dir = gcov/run_<scenario_id>/
```
## 五、向后兼容性
### 5.1 旧版目录迁移
| 旧版目录 | 新版目录 | 迁移方式 |
|----------|----------|----------|
| `main/input/` | `cobol/main/input/` | 移动文件 |
| `main/output/` | `cobol/main/output/` | 移动文件 |
| `main/json/` | `cobol/main/json/` | 移动文件 |
| `skip/input/` | `cobol/run_skip/input/` | 重命名+移动 |
| `skip/output/` | `cobol/run_skip/output/` | 重命名+移动 |
| `skip/json/` | `cobol/run_skip/json/` | 重命名+移动 |
| `pre_src/` | `cobol/pre_src/` | 移动文件 |
| `coverage/` | `coverage/` | 保持不变 |
| `logs/` | `logs/` | 保持不变 |
| `gcov/` | `gcov/` | 保持不变 |
| `data/` | `data/` | 保持不变 |
### 5.2 兼容性处理
```python
def _ensure_cobol_dir_structure(runtime_dir):
"""确保cobol目录结构存在,兼容旧版"""
cobol_dir = runtime_dir / "cobol"
if not cobol_dir.exists():
# 检查是否是旧版结构(main/直接在runtime_dir下)
old_main = runtime_dir / "main"
if old_main.exists():
# 迁移到新结构
shutil.move(str(old_main), str(cobol_dir / "main"))
```
## 六、黑盒测试映射
### 6.1 YAML配置示例
```yaml
# config/programs/KIN08DBU.yaml
runs:
- id: normal
sysin:
- { dd: KIN08S01, content: "..." }
- id: no_period
sysin:
- { dd: KIN08S01, content: "..." }
- id: insert_error
inject_duplicate_pk: true
sysin:
- { dd: KIN08S01, content: "..." }
- id: sql_delete_error
sysin:
- { dd: KIN08S01, content: "..." }
- id: sql_select_error
sysin:
- { dd: KIN08S01, content: "..." }
```
### 6.2 目录映射
| 场景ID | COBOL目录 | Java目录 | 日志文件 | gcov目录 | 数据库文件 |
|--------|-----------|----------|----------|----------|------------|
| normal | `cobol/run_normal/` | `java/run_normal/output/` | `logs/run_normal.log` | `gcov/run_normal/` | `data/kin_normal.db` |
| no_period | `cobol/run_no_period/` | `java/run_no_period/output/` | `logs/run_no_period.log` | `gcov/run_no_period/` | `data/kin_no_period.db` |
| insert_error | `cobol/run_insert_error/` | `java/run_insert_error/output/` | `logs/run_insert_error.log` | `gcov/run_insert_error/` | `data/kin_insert_error.db` |
| sql_delete_error | `cobol/run_sql_delete_error/` | `java/run_sql_delete_error/output/` | `logs/run_sql_delete_error.log` | `gcov/run_sql_delete_error/` | `data/kin_sql_delete_error.db` |
| sql_select_error | `cobol/run_sql_select_error/` | `java/run_sql_select_error/output/` | `logs/run_sql_select_error.log` | `gcov/run_sql_select_error/` | `data/kin_sql_select_error.db` |
### 6.3 黑盒测试执行流程
1. **编译阶段**:编译一次,全场景共享 `.exe``.gcno`
2. **场景执行**:对每个场景独立执行
- 生成场景特定输入数据
- 初始化场景特定DB
- 运行COBOL程序
- 收集场景特定gcov数据
3. **Java执行**:使用最后一个场景的DB结果
4. **验证比对**:比较COBOL和Java输出
5. **覆盖率合并**:合并多轮gcov数据,生成覆盖率报告
### 6.4 测试报告生成
| 报告类型 | 生成方式 | 输出位置 |
|----------|----------|----------|
| 覆盖率HTML报告 | `orchestrator_db.generate_coverage_report()` | `coverage/<PROGRAM_ID>_coverage.html` |
| 测试结果JSON | `orchestrator.run_all()` | `reports/<timestamp>/result.json` |
| 测试报告HTML | `ReportGenerator.generate_html()` | `reports/<timestamp>/report.html` |
| 机器可读JSON | `ReportGenerator.generate_machine_json()` | `reports/<timestamp>/machine.json` |
## 七、代码修改清单
### 7.1 orchestrator_db.py
| 行号 | 修改内容 | 说明 |
|------|----------|------|
| 103 | `runtime_dir = v3_root / "output" / program_id / "cobol"` | 添加cobol子目录 |
| 594-596 | `run_label = "main" if not scenario else f"run_{scenario.id}"` | 统一场景目录命名 |
| 626-628 | `env_overrides` 路径改为 `"input"``"output"` | 移除main/层级 |
| 686 | `log_dir = self.runtime_dir.parent / "logs"` | 日志目录移到根目录 |
| 700 | `gcda_dst_dir = gcov_dir / run_label` | 统一gcov目录命名 |
| 769 | `output_dir = v3_root / "output" / self.program_id / "coverage"` | 覆盖率报告移到根目录 |
| 779 | `gcov_dir = self.runtime_dir.parent / "gcov"` | gcov目录移到根目录 |
| 975 | `java_out = self.runtime_dir.parent / "java" / run_label / "output"` | Java输出目录 |
| 1016 | `self.java_output_path = self.runtime_dir.parent / "java" / run_label / "output"` | Java输出路径 |
### 7.2 cobol_testgen/__init__.py
| 行号 | 修改内容 | 说明 |
|------|----------|------|
| 1759 | `outpath = prog_outdir / 'cobol' / 'main' / 'json'` | JSON输出路径 |
| 1769 | `prog_outdir / 'cobol' / 'main' / 'input'` | 输入文件路径 |
| 1776 | `prog_outdir / 'cobol' / 'main' / 'input'` | 子程序输入路径 |
| 1796 | `prog_outdir / 'cobol' / 'run_skip' / 'json'` | Skip JSON路径 |
| 1802 | `prog_outdir / 'cobol' / 'run_skip' / 'input'` | Skip输入路径 |
### 7.3 cobol_testgen/runner.py
| 行号 | 修改内容 | 说明 |
|------|----------|------|
| 425-426 | `Path(outdir) / 'cobol' / 'main' / 'input'` | 主场景输入路径 |
| 425-426 | `Path(outdir) / 'cobol' / 'main' / 'output'` | 主场景输出路径 |
| 430-431 | `Path(outdir) / 'cobol' / 'run_skip' / 'input'` | Skip场景输入路径 |
| 430-431 | `Path(outdir) / 'cobol' / 'run_skip' / 'output'` | Skip场景输出路径 |
### 7.4 runners/gixsql_runner.py
| 行号 | 修改内容 | 说明 |
|------|----------|------|
| 308 | `debug_dir = ... / "cobol" / "pre_src"` | 预处理源码路径 |
### 7.5 orchestrator.py
| 行号 | 修改内容 | 说明 |
|------|----------|------|
| 142 | `co = Path(f"output/{cfg.program}/cobol/main/output/cobol_out.bin")` | COBOL输出路径 |
| 159 | `java_out_dir = Path("output") / cfg.program / "java" / "main" / "output"` | Java输出路径 |
| 200 | `rd = Path(f"output/{vr.program}/reports") / vr.timestamp` | 报告输出路径 |
## 八、测试验证
### 8.1 单元测试
运行现有单元测试确保向后兼容:
```bash
python -m pytest tests/ -v
```
### 8.2 集成测试
运行黑盒测试验证目录结构:
```bash
cd test-data
python s15_coverage_verification.py
python s30_db_e2e.py
```
### 8.3 手动验证
检查目录结构是否正确:
```bash
# 检查单轮程序
ls -la output/KIN01INP/
ls -la output/KIN01INP/cobol/main/
ls -la output/KIN01INP/java/main/output/
# 检查多轮程序
ls -la output/KIN08DBU/
ls -la output/KIN08DBU/cobol/run_normal/
ls -la output/KIN08DBU/java/run_normal/output/
```
## 九、注意事项
1. **env_overrides 路径**:修改后需要确保COBOL运行时能找到正确的文件
2. **SQLite数据库路径**:多轮场景的DB文件需要按场景命名
3. **gcov数据合并**:多轮场景的gcov数据需要正确合并
4. **向后兼容**:需要处理旧版目录结构的迁移
5. **测试覆盖**:修改后需要运行所有测试确保功能正常
---
**文档版本**v1.0
**创建日期**2026-09-05
**最后更新**2026-09-05