Metadata-Version: 2.4
Name: omni-engine
Version: 1.1.2.16
Summary: 一个Python测试执行引擎/框架，以MinIO为demo，实现UI、API、MC命令行、可靠性等自动化测试
Home-page: https://gitee.com/omni-platform/omni-engine.git
Author: TXU
Author-email: tao.xu2008@outlook.com
Maintainer: TXU
Maintainer-email: tao.xu2008@outlook.com
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Pytest
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Testing
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Operating System :: OS Independent
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: pytest>=9.0
Requires-Dist: allure-pytest
Requires-Dist: allure-python-commons>=2.16.0
Requires-Dist: pytest-html>=4.0
Requires-Dist: pytest-dependency
Requires-Dist: pytest-flexreport
Requires-Dist: pytest-json-report
Requires-Dist: Faker>=20
Requires-Dist: requests>=2.32
Requires-Dist: requests-toolbelt>=1.0
Requires-Dist: urllib3>=2.0
Requires-Dist: jsonpath>=0.82
Requires-Dist: jmespath>=1.0
Requires-Dist: PyYAML>=6.0
Requires-Dist: configparser>=7.2.0
Requires-Dist: selenium>=4.30
Requires-Dist: webdriver-manager>=4.0
Requires-Dist: Appium-Python-Client>=4.1.0
Requires-Dist: paramiko>=3.5
Requires-Dist: scp>=0.15
Requires-Dist: PyMySQL>=1.1
Requires-Dist: SQLAlchemy>=2.0
Requires-Dist: typer>=0.25
Requires-Dist: prettytable>=3.0
Requires-Dist: progressbar>=2.5
Requires-Dist: Jinja2>=3.1
Requires-Dist: MarkupSafe>=3.0
Requires-Dist: loguru>=0.7
Requires-Dist: arrow>=1.4.0
Requires-Dist: filelock>=3.10
Requires-Dist: filetype>=1.2
Requires-Dist: python-jenkins>=1.8
Requires-Dist: pypinyin>=0.44
Requires-Dist: setuptools~=82.0.1
Requires-Dist: xmindparser>=1.2
Requires-Dist: openai>=1.0.0
Requires-Dist: playwright>=1.56
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: maintainer
Dynamic: maintainer-email
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# omni-engine

#### 介绍
**Omni 测试平台执行引擎** — 全功能自动化测试框架，基于 Python 编写，以 MinIO 为 Demo 实现多类型自动化测试。

支持测试类型：功能测试、API 测试、UI 测试、CLI 测试、DFX 测试、APP 测试、服务端测试、自定义组合测试等。

> 仓库地址：https://gitee.com/omni-platform/omni-engine  
> 版本：v1.1.2 | 语言：Python >= 3.9 | 协议：MIT

---

#### 快速导航

- [安装指南](#安装指南)
- [项目脚手架](#项目脚手架)
- [配置文件详解](#配置文件详解)
- [编写测试用例](#编写测试用例)
- [执行测试](#执行测试)
- [自定义执行器（引擎插件）](#自定义执行器引擎插件)
- [测试报告](#测试报告)
- [高级配置](#高级配置)
- [Demo 项目](#demo-项目)
- [目录结构](#目录结构)
- [依赖概览](#依赖概览)

---

## 安装指南

### 方式一：从 PyPI 安装（仅框架核心，不含 demo）

```bash
pip install omni-engine
```

> PyPI 包不包含 demo 演示项目，适用于已有项目引入框架。

### 方式二：从源码仓库安装（包含 demo）

```bash
# 克隆仓库
git clone https://gitee.com/omni-platform/omni-engine.git
cd omni-engine

# 创建虚拟环境（推荐）
python -m venv venv
# Windows
venv\Scripts\activate
# Linux/Mac
source venv/bin/activate

# 安装依赖和框架
pip install -r requirements.txt
pip install -e .
```

### 方式三：快速体验 demo

```bash
git clone https://gitee.com/omni-platform/omni-engine.git
cd omni-engine
pip install -r requirements.txt
pip install -e .
python run_main.py -f ./demo/conf/demo.xml``

### 额外依赖说明

| 功能 | 依赖 | 说明 |
|------|------|------|
| Allure 报告 | Java 运行时 + Allure CLI | 报告生成需要，参考 [Allure 文档](https://docs.qameta.io/allure-report/) |
| Web UI 测试 | Chrome/Firefox + 对应 WebDriver | 脚手架创建项目时会自动下载 |
| APP 测试 | Appium 服务端 | 参考 [Appium 文档](https://appium.io/docs/) |

#### Allure 依赖说明

Allure 报告生成依赖 Java 运行环境和 Allure CLI，安装方式：

```bash
# 1. 安装 Java（推荐 Java 11+）
# https://adoptium.net/

# 2. Allure 会自动下载到项目 bin/allure/ 目录（创建项目时）
# 或手动安装：
#   Windows: scoop install allure
#   macOS: brew install allure
#   Linux: 从 https://github.com/allure-framework/allure2/releases 下载
```

---

## 项目脚手架

### 创建新项目

```bash
# 创建新测试项目（自动下载 ChromeDriver 和 Allure）
python manage.py --project my_project

# 创建 demo 项目（完整演示工程）
python manage.py --project demo
```

脚手架创建的项目结构：

```
my_project/
├── conf/                          # 配置文件
│   ├── settings.ini               #   全局配置（数据库、日志、Allure 等）
│   ├── debug.xml                  #   测试配置（调试用）
│   ├── testbed/                   #   测试环境定义
│   │   └── testbed_debug.xml
│   └── testset/                   #   测试集定义
│       └── testset_debug.xml
├── bin/                           # 二进制依赖
│   ├── webdrivers/                #   WebDriver（脚手架自动下载）
│   │   └── chromedriver.exe
│   └── allure/                    #   Allure CLI（脚手架自动下载）
│       └── bin/
│           └── allure.bat
├── data/                          # 测试数据
│   └── data_sample.json
├── testcase/                      # 测试用例目录
│   └── __init__.py
├── reports/                       # 测试报告输出
├── conftest.py                    # pytest 夹具
├── pytest.ini                     # pytest 配置
├── run_main.py                    # 测试执行入口
└── __init__.py
```

### 安装 WebDriver

```bash
# 安装 ChromeDriver
python manage.py --install chrome

# 安装其他浏览器驱动
python manage.py --install firefox
python manage.py --install edge
```

---

## 配置文件详解

### 三层配置体系

框架采用 XML + INI 双层驱动：

```
settings.ini  →  全局/项目级配置（数据库、日志、Allure 路径）
    ↓
demo.xml      →  测试主配置（指定 testbed 和 testset）
    ↓
testbed.xml   →  测试环境定义（被测服务节点、客户端）
testset.xml   →  测试集定义（要执行的用例集合）
```

### settings.ini 配置

```ini
[LOGGER]
file_level = INFO          ; 日志文件等级
console_level = INFO       ; 控制台日志等级
max_rotation = 100 MB      ; 日志滚动大小
max_retention = 30 days    ; 日志保留天数

[HEADERS]
User-Agent = Mozilla/5.0 ...  ; 默认请求头

[DATABASES]
ENGINE = django.db.backends.sqlite3  ; 数据库引擎
NAME = db.sqlite3                    ; 数据库路径

[JENKINS]
url = http://jenkins:8080/
user = tester
password = ****
job_name = test-platform-report
token = ****

[ZENTAO]
url = https://chandao.cn/zentao/
user = tester
password = ****

[ALLURE]
; allure 可执行文件路径，留空则按以下顺序查找：
; 1. 此配置项
; 2. PATH 环境变量
; 3. 项目 bin/allure/bin/allure.bat
bin_path =
```

配置文件查找优先级：`项目目录/conf/settings.ini` > `框架默认 settings.ini`。

### testconf（主配置）

```xml
<testconf desc="测试描述">
    <testbed>conf/testbed/testbed_demo.xml</testbed>
    <testset>conf/testset/testset_demo.xml</testset>
</testconf>
```

### testbed（测试环境）

```xml
<testbed desc="测试环境">
    <env desc="环境1">
        <server ip="192.168.1.100" user="root" password="****"/>
        <client ip="192.168.1.101" user="root" password="****"/>
    </env>
</testbed>
```

### testset（测试集）

```xml
<testset desc="测试集">
    <!-- 运行整个目录下的用例 -->
    <case location="testcase/om/login/"/>

    <!-- 运行单个用例文件 -->
    <case location="testcase/restapi/login/test_restapi_login.py"/>

    <!-- 运行指定类 -->
    <case location="testcase/om/login/test_om_login.py::TestCaseUILogin"/>

    <!-- 排除特定用例 -->
    <case location="testcase/om/login/test_om_login.py" exclude="test002"/>
</testset>
```

---

## 编写测试用例

### 编写规范

1. **测试文件**：放置在 `testcase/` 目录下，以 `test_` 开头
2. **测试类**：继承 `ApiRunner` / `WebRunner` / `CmdRunner` 等，以 `Test` 开头
3. **测试方法**：以 `test_` 开头，一个方法 = 一个测试用例
4. **步骤方法**：非 `test_` 开头的 def（通过 `StepMetaClass` 自动装饰为 Allure 步骤）
5. **前后置**：`setup_class` / `teardown_class` / `setup_method` / `teardown_method`

### API 测试用例

```python
from omni.engine import ApiRunner
from omni.engine.api import RunRequest, ApiStep


class TestLogin(ApiRunner):
    """登录模块接口测试"""

    def setup_class(self):
        super().start_class()

    def teardown_class(self):
        super().end_class()

    def test_login_success(self):
        """正常登录"""
        step = ApiStep(
            "登录接口",
            RunRequest("POST", "/api/login")
            .set_body({"username": "admin", "password": "123456"})
            .assert_status_code(200)
            .assert_json("code", 0)
            .assert_json("data.token", lambda x: len(x) > 0)
        )
        self.run_step(step)

    def test_login_wrong_password(self):
        """错误密码登录"""
        step = ApiStep(
            "错误密码登录",
            RunRequest("POST", "/api/login")
            .set_body({"username": "admin", "password": "wrong"})
            .assert_status_code(200)
            .assert_json("code", -1)
        )
        self.run_step(step)
```

### Web UI 测试用例

```python
from omni.engine import WebRunner


class TestLogin(WebRunner):
    """Web 登录测试"""

    def setup_class(self):
        super().start_class()

    def test_login_page(self):
        """访问登录页面"""
        self.driver.get("http://192.168.1.100:9090/login")
        self.wait_element_display("id", "username")
        self.input("id", "username", "admin")
        self.input("id", "password", "123456")
        self.click("id", "login-btn")
        self.assert_text_display("id", "welcome")

    def test_create_bucket(self):
        """创建存储桶"""
        self.click("xpath", "//button[contains(text(), '新建')]")
        self.input("name", "bucketName", "my-bucket")
        self.click("xpath", "//span[contains(text(), '确认')]")
        self.wait_element_display("xpath", "//td[contains(text(), 'my-bucket')]")
```

### CLI 命令行测试用例

```python
from omni.engine import CmdRunner


class TestMcCommand(CmdRunner):
    """mc 命令行测试"""

    def test_mc_ls(self):
        """列出存储桶"""
        result = self.run_cmd("./mc ls myminio")
        self.assert_in("bucket1", result.stdout)

    def test_mc_cp(self):
        """上传文件"""
        self.run_cmd("echo 'test data' > test.txt")
        result = self.run_cmd("./mc cp test.txt myminio/test-bucket/")
        self.assert_in("Total", result.stdout)
```

### 组合测试（API + CLI + UI 混合）

```python
from omni.engine import ApiRunner, CmdRunner


class TestMixedScenario(ApiRunner, CmdRunner):
    """混合场景测试"""

    def test_end_to_end(self):
        """端到端场景：API 创建资源 → CLI 验证 → UI 检查"""
        # API 步骤
        step = ApiStep(
            "API 创建存储桶",
            RunRequest("POST", "/api/buckets")
            .set_body({"name": "test-bucket"})
            .assert_status_code(200)
        )
        self.run_step(step)

        # CLI 步骤
        result = self.run_cmd("./mc ls myminio")
        self.assert_in("test-bucket", result.stdout, "CLI 验证桶已创建")

        # UI 步骤
        self.driver.get("http://portal:9090/buckets")
        self.assert_text_display("xpath", "//td[contains(text(), 'test-bucket')]")
```

### StepMetaClass — 自动装饰步骤方法

继承 `ApiRunner`/`CmdRunner` 等 Runner（其基类 `BaseEngine` 已内置 `StepMetaClass`）后，类中**所有非 `__` 开头的方法**（包括非 `test_` 方法）会被自动装饰为 Allure 步骤，无需显式声明元类：

```python
from omni.engine import ApiRunner


class TestBucket(ApiRunner):
    """存储桶测试"""

    def _login(self):
        """登录系统"""  # 此 docstring 会成为 Allure 步骤名称
        step = ApiStep("登录", RunRequest("POST", "/api/login").set_body(...))
        self.run_step(step)

    def _create_bucket(self, name):
        """创建存储桶"""
        step = ApiStep("创建桶", RunRequest("POST", "/api/buckets").set_body({"name": name}))
        self.run_step(step)

    def test_create_and_delete(self):
        """创建并删除存储桶"""
        self._login()           # 自动装饰为 Allure 步骤 "登录系统"
        self._create_bucket("test-001")  # 自动装饰为 Allure 步骤 "创建存储桶"
```

### 数据驱动测试

```python
import pytest
from omni.engine import ApiRunner
from omni.engine.api import RunRequest, ApiStep


class TestUserDataDriven(ApiRunner):
    """数据驱动测试"""

    @pytest.mark.parametrize("username, password, expected_code", [
        ("admin", "123456", 0),
        ("user1", "pass1", 0),
        ("", "123456", -1),
        ("admin", "", -1),
    ])
    def test_login_parametrize(self, username, password, expected_code):
        """参数化登录测试"""
        step = ApiStep(
            f"登录({username})",
            RunRequest("POST", "/api/login")
            .set_body({"username": username, "password": password})
            .assert_json("code", expected_code)
        )
        self.run_step(step)
```

### 使用 TestCaseBase 原生断言

框架的 `TestCaseBase` 提供 unittest 风格的丰富断言方法：

```python
from omni import TestCaseBase


class TestAssertions(TestCaseBase):
    """断言示例"""

    def test_assertions(self):
        self.assertEqual(1, 1)
        self.assertIn("hello", "hello world")
        self.assertGreater(5, 3)
        self.assertDictEqual({"a": 1}, {"a": 1})
        self.assertIsInstance([], list)
```

---

## 执行测试

### 命令行执行

```bash
# 默认执行 demo 测试
python run_main.py

# 指定配置文件执行
python run_main.py -f ./demo/conf/demo.xml

# 指定日志级别
python run_main.py -f ./demo/conf/demo.xml --loglevel DEBUG

# 只收集用例不执行（统计用例数）
python run_main.py -f ./demo/conf/demo.xml --collect-only

# 执行并生成 Allure 报告
python run_main.py -f ./demo/conf/demo.xml --report-allure

# 指定测试描述
python run_main.py -f ./demo/conf/demo.xml --desc "冒烟测试 v1.0"
```

### CLI 参数参考

| 参数 | 简写 | 默认值 | 说明 |
|------|------|--------|------|
| `--test_conf_path` | `-f` | `./demo/conf/demo.xml` | 配置文件路径 |
| `--loglevel` | | `INFO` | 日志等级：TRACE/DEBUG/INFO/SUCCESS/WARNING |
| `--report_allure` | | `False` | 本地生成 Allure 报告 |
| `--collect-only` | | `False` | 只收集用例不执行 |
| `--jenkins_workspace` | | `""` | Jenkins workspace 路径 |
| `--desc` | | `""` | 测试描述 |
| `--version` | `-v` | | 显示版本信息 |
| `--omni-json-report` | | `False` | 输出结构化 JSON 报告（用于 omni-test-platform 回调） |
| `--omni-json-report-file` | | `""` | JSON 报告输出路径（默认写入 reports 目录） |

### 平台集成 (omni-test-platform)

omni-engine 与 omni-test-platform（omni-server + omni-web）深度集成，支持以下功能：

#### 用例同步

`omni-engine-sync` 命令扫描项目中的测试方法，生成清单并推送到平台：

```bash
# 扫描并推送用例到平台
omni-engine-sync sync \
  --server http://platform:8080 \
  --token your-personal-access-token \
  --project-id 1 \
  --project-root ./demo

# 仅扫描预览，不推送
omni-engine-sync sync --server http://platform:8080 --token xxx --dry-run
```

#### 结构化 JSON 报告（回调）

集成 pytest 插件 `--omni-json-report`，在执行时生成平台可消费的结构化报告：

```bash
# 执行测试并生成 JSON 报告
python run_main.py -f ./demo/conf/demo.xml --omni-json-report

# 指定报告输出路径
pytest demo/testcase/ --omni-json-report --omni-json-report-file=./reports/result.json
```

JSON 报告格式示例：

```json
{
  "task_id": "",
  "start_time": 1715846400000,
  "end_time": 1715847000000,
  "total": 10,
  "passed": 8,
  "failed": 1,
  "skipped": 1,
  "results": [
    {
      "zen_tao_case_id": 123,
      "method_name": "test_login",
      "class_name": "TestLogin",
      "status": "passed",
      "duration_ms": 1523,
      "error_msg": "",
      "log_path": "",
      "allure_uuid": ""
    }
  ]
}
```

该报告通过 omni-engine 的回调接口（`POST /api/v1/at/cases/callback`）发送到 omni-server，关联到流水线阶段执行记录。

#### 平台生态总览

```
omni-web (管理界面)
    ↕ HTTP API
omni-server (后端服务)
    ↕ WebSocket/Polling    ↕ SSH/PUSH                  ↕ HTTP Callback
Jenkins (CI执行)      Testbed 环境节点         omni-engine (测试执行引擎)
                                                    ↕ pytest 插件
                                              JSON Report → 回调平台结果
```

### Jenkins 集成

在 Jenkins 中配置构建步骤：

```bash
# 执行测试
python run_main.py -f ${PROJECT}/conf/${TEST_CONF}.xml \
    --jenkins_workspace ${WORKSPACE} \
    --desc "${BUILD_TAG}"

# 生成 Allure 报告（由 Jenkins Allure 插件处理）
```

Jenkins 端需要安装 Allure 插件，配置 Allure 路径指向 Jenkins 全局工具配置中的 Allure CLI。

### pytest 原生执行

```bash
# 直接执行指定用例文件
pytest demo/testcase/restapi/login/test_restapi_login.py -v -s

# 执行并生成 Allure 报告
pytest demo/testcase/restapi/login/test_restapi_login.py \
    --alluredir=./reports/allure-results --clean-alluredir

# 查看 Allure 报告
allure serve ./reports/allure-results
```

### CLI 接口测试执行（新增）

框架新增 `omni api` 子命令组，支持单接口调试、用例文件执行、批量执行：

```bash
# 执行 JSON 用例文件
python -m omni api run demo/cases/httpbin_api.json -v

# 单接口调试
python -m omni api execute --method GET --url https://httpbin.org/ip

# 批量执行目录下用例
python -m omni api batch demo/cases/
```

支持的新步骤类型：`API` / `SHELL` / `SCRIPT` / `SLEEP` / `SQL` / `gRPC` / `WebSocket`

详细文档见 [引擎增强 v2 →](docs/engine_enhancement_v2.md)

### E2E 独立验证

```bash
# 直接运行端到端验证脚本（无需框架初始化）
python demo/cases/run_e2e_demo.py
```

输出示例：
```
============================================================
  OmniEngine Phase 1 — E2E 验证
============================================================
  [PASS] Shell 执行器 — echo "e2e demo OK"
  [PASS] Script 执行器 — 42*2=84
  [PASS] Sleep 执行器 — 实际 0.201s
  [PASS] SQL 执行器 — 3 条记录
  [PASS] Runner 分发 — 3 steps
  [PASS] ResultSerializer
  [PASS] CallbackReporter
  [PASS] ApiExecutor
  总计: 8/8 通过
```

---

## 自定义执行器（引擎插件）

框架提供插件机制，通过 `EngineRegistry` 注册自定义执行器，支持两种方式。

### 方式一：装饰器注册

```python
from omni.engine import BaseEngine, StepResult, EngineRegistry


@EngineRegistry.register("MYSQL")
class MysqlRunner(BaseEngine):
    """MySQL 数据库测试执行器"""
    step_type = "MYSQL"
    description = "MySQL 数据库操作测试"

    def __init__(self):
        self.connection = None

    def setup_class(cls):
        """类级前置：建立数据库连接"""
        pass

    def run_step(self, step_data) -> StepResult:
        """
        执行 SQL 步骤

        Args:
            step_data: {"sql": "SELECT * FROM users", "expected": [...]}
        """
        try:
            cursor = self.connection.cursor()
            cursor.execute(step_data["sql"])
            result = cursor.fetchall()
            return StepResult(
                success=True,
                step_name="SQL 查询",
                step_type="MYSQL",
                data=result,
            )
        except Exception as e:
            return StepResult(
                success=False,
                step_name="SQL 查询",
                step_type="MYSQL",
                error=str(e),
            )
```

注册后即可在测试用例中作为执行器使用：

```python
class TestDatabase(MysqlRunner):
    def test_query_users(self):
        result = self.run_step({"sql": "SELECT * FROM users"})
        self.assertTrue(result.success)
```

### 方式二：setuptools entry_points 自动发现

创建独立的插件包，在 `setup.py` 中声明：

```python
setup(
    ...
    entry_points={
        "omni_engine.plugins": [
            "my-engine = my_package.my_engine:MyEngine",
        ],
    },
)
```

框架在 import 时会自动发现并注册插件。

### 内置引擎参考

| 引擎 | step_type | 说明 |
|------|-----------|------|
| `ApiRunner` | `API` | REST API 接口测试 |
| `WebRunner` | `WEB` | Selenium Web UI 测试 |
| `CmdRunner` | `CMD` | 命令行/SSH 远程执行 |
| `AppRunner` | `APP` | Appium APP 测试 |
| `KubectlRunner` | `KUBECTL` | Kubernetes CLI 操作 |
| `OmmCliRunner` | `OMM` | OMM 平台管理 CLI |

#### v2 步骤执行器（新增）

| 执行器 | step_type | 说明 |
|--------|-----------|------|
| `ShellExecutor` | `SHELL` | 系统 Shell 命令执行 |
| `ScriptExecutor` | `SCRIPT` | Python 内联脚本执行 |
| `SleepExecutor` | `SLEEP` | 等待指定时间 |
| `SQLExecutor` | `SQL` | MySQL/SQLite 数据库操作 |
| `GrpcExecutor` | `gRPC` | gRPC 服务调用 |
| `WsExecutor` | `WebSocket` | WebSocket 通信 |

### 实现自定义引擎的要求

实现 `BaseEngine` 子类必须：

1. 设置 `step_type` 类属性（唯一标识）
2. 实现 `run_step(self, step_data) -> StepResult` 抽象方法
3. 可选重载 `setup_class / teardown_class / setup / teardown` 生命周期钩子

`StepResult` 返回值说明：

| 字段 | 类型 | 说明 |
|------|------|------|
| `success` | bool | 步骤是否成功 |
| `step_name` | str | 步骤名称 |
| `step_type` | str | 引擎类型标识 |
| `status` | TestStatusEnum | 测试状态（passed/failed/error/skipped） |
| `data` | Any | 步骤产生的原始数据 |
| `export_vars` | dict | 导出到上下文的变量 |
| `error` | str | 失败/异常时的错误信息 |
| `duration` | float | 执行耗时（秒） |

---

## 测试报告

### 报告类型

| 报告 | 格式 | 生成方式 |
|------|------|----------|
| Allure 报告 | HTML | `--report-allure` 或 Jenkins Allure 插件 |
| HTML 报告 | 自包含 HTML | 自动生成（pytest-flexreport） |
| JSON 报告 | JSON | 自动生成（pytest-json-report） |
| 日志报告 | HTML | 自动生成（步骤日志转 HTML） |

### Allure 报告特性

- 测试步骤自动分层（Suite → Test → Step）
- 支持自定义报告标题和 Overview 名称
- 支持报告历史趋势（`prepare_history`）
- 环境信息自动注入（`environment.properties`）
- 支持 Jenkins 集成（Allure 插件）

### 报告输出位置

```
reports/
└── {project}/
    └── {report_id}_{timestamp}/
        ├── log/                  # 测试日志
        ├── html/                 # HTML 报告
        ├── json/                 # JSON 报告
        └── allure-results/       # Allure XML 结果
```

---

## 高级配置

### settings.ini 完整配置项

```ini
[LOGGER]
; 日志配置
file_level = INFO           ; 文件日志等级
console_level = INFO        ; 控制台日志等级
max_rotation = 100 MB       ; 日志文件滚动大小
max_retention = 30 days     ; 日志保留时间

[DATABASES]
; 数据库配置 — 测试结果持久化
ENGINE = django.db.backends.sqlite3  ; sqlite3 / mysql
NAME = db.sqlite3                    ; sqlite3 路径 或 mysql 库名

[HEADERS]
; 默认请求头
User-Agent = Mozilla/5.0 ...

[JENKINS]
; Jenkins 集成配置
url = http://jenkins:8080/
user = tester
password = ****
job_name = test-platform-report
token = ****

[ZENTAO]
; 禅道缺陷管理集成
url = https://chandao.cn/zentao/
user = tester
password = ****

[ALLURE]
; Allure CLI 路径配置
; 留空时依次查找：settings.ini > PATH 环境变量 > 项目 bin/allure/bin/
bin_path =
```

项目级配置覆盖：在 `{项目目录}/conf/settings.ini` 中设置同名配置项会覆盖框架默认值。

### 配置查找优先级

```
项目 conf/settings.ini      ← 最高优先级（覆盖默认值）
      ↓
框架 omni/config/settings.ini  ← 默认配置
```

### 环境变量

通过 testbed XML 定义的服务器/客户端信息，可以在用例中通过 `GlobalContext` 访问：

```python
from omni.context import GlobalContext

# 获取测试环境信息
envs = GlobalContext.envs
server_ip = envs[0].node_list[0]['ip']
client_ip = envs[0].client_list[0]['ip']
```

### 上下文变量

框架提供线程安全的上下文变量管理，适用于跨步骤/跨用例的数据传递：

```python
from omni.context import GlobalContext

# 注册并设置上下文变量
GlobalContext.register('token')
GlobalContext.set('token', {'id': 1, 'name': 'Alice'})
# 获取
token = GlobalContext.get('token')
# 重置
GlobalContext.reset('token')
```

### 测试结果数据库

框架自动使用 SQLite（或 MySQL）记录每次测试构建的结果：

- 测试报告汇总（`TestReport`）
- 测试用例明细（`TestCase`）
- 支持按 ID 查询报告

---

## Demo 项目

Demo 以 **MinIO** 对象存储项目为例，完整演示了框架的各种测试能力。

### Demo 环境搭建

```bash
# 1. 下载 MinIO
# https://dl.min.io/server/minio/release/

# 2. 启动 MinIO 服务
minio.exe server D:\data\ --console-address 127.0.0.1:9001

# 3. 执行 Demo 测试
python run_main.py -f ./demo/conf/demo.xml --report-allure
```

### Demo 涵盖的场景

| 测试类型 | 场景 | 示例 |
|----------|------|------|
| Web UI | OM 平台操作 | 登录、创建桶、上传文件、文件共享 |
| REST API | 平台接口验证 | 登录 API、文件存储 API、池管理 API |
| CLI | mc 命令行 | mc ls、mc cp、mc admin |
| 协议 | S3 / POSIX | S3 SDK 接口调用、POSIX 文件操作 |
| 文件存储 | 共享协议 | NFS 挂载、CIFS、FUSE |
| 可靠性与可服务性 | 系统容错 | 网络抖动测试、FlashOver |
| 性能 | 基准测试 | 对象存储性能测试 |
| 工具集 | 部署/升级/清理 | 平台部署、升级、测试清理 |

### Demo 项目结构

```
demo/
├── conf/                       # 配置文件
│   ├── demo.xml                #   主配置
│   ├── e2e_demo.xml            #   引擎增强测试配置（新增）
│   ├── settings.ini            #   项目级配置
│   ├── testbed/                #   测试环境
│   │   └── testbed_e2e.xml     #   引擎增强测试床（新增）
│   └── testset/                #   测试集
│       └── testset_e2e.xml     #   引擎增强测试集（新增）
├── cases/                      # JSON 用例文件（新增）
│   ├── httpbin_api.json        #   HTTP API 测试用例
│   ├── multi_step_demo.json    #   多步骤混合编排用例
│   └── run_e2e_demo.py         #   E2E 验证脚本
├── features/                   # 业务层封装（Page Object 模式）
│   ├── om/web/                 #   OM 平台 Web UI
│   │   ├── login/
│   │   └── object_store/
│   ├── om/api/                 #   OM 平台 API
│   ├── cli/mc/                 #   mc 命令行
│   ├── restapi/                #   REST API
│   └── toolkit/                #   工具集
├── resources/                  # 资源封装（多步骤高度封装）
│   └── res_om.py
├── testcase/                   # 测试用例
│   ├── om/                     #   OM 平台
│   ├── restapi/                #   REST API
│   ├── cli/                    #   CLI 测试
│   ├── api/                    #   引擎增强测试（新增）
│   │   └── test_step_executors_demo.py
│   ├── protocol/               #   协议测试
│   ├── reliability/            #   可靠性测试
│   └── value_added/            #   增值特性
├── bin/webdrivers/             # WebDriver 二进制
├── conftest.py                 # pytest 夹具
└── pytest.ini                  # pytest 配置
```

---

## 目录结构

```
├── omni/                       # 核心框架
│   ├── cli/                    # 命令行入口
│   │   ├── main.py             #   - 测试执行 CLI（typer）+ omni api 子命令
│   │   ├── api_cmd.py          #   - api 子命令组（execute/run/batch）【新增】
│   │   ├── manage.py           #   - 项目管理 CLI（脚手架、驱动安装）
│   │   └── sync.py             #   - 平台同步 CLI
│   ├── common/                 # 公用组件
│   │   ├── case.py             #   - 用例基类（unittest 兼容断言）
│   │   ├── meta_class.py       #   - StepMetaClass 元类
│   │   ├── decorators.py       #   - 装饰器
│   │   ├── exceptions.py       #   - 异常定义
│   │   └── log.py              #   - 日志（loguru）
│   ├── config/                 # 配置
│   │   ├── settings.ini        #   - 默认全局配置
│   │   ├── conf_parser.py      #   - XML/INI/YAML 配置解析
│   │   └── version.py          #   - 版本
│   ├── context/                # 上下文管理
│   │   ├── global_context.py   #   - 全局上下文（单例）
│   │   ├── ctx_vars.py         #   - 线程安全上下文变量
│   │   ├── services.py         #   - 配置/环境/统计服务
│   │   ├── cache.py            #   - 缓存
│   │   ├── call_tree_node.py   #   - 调用树
│   │   └── db.py               #   - 结果数据库
│   ├── engine/                 # 测试引擎
│   │   ├── registry.py         #   - 插件注册表
│   │   ├── base.py             #   - 引擎基类 & StepResult
│   │   ├── api/                #   - API 引擎
│   │   ├── web/                #   - Web UI 引擎（Selenium）
│   │   ├── cmd/                #   - CLI 引擎
│   │   ├── app/                #   - APP 引擎（Appium）
│   │   ├── kubectl/            #   - Kubernetes CLI
│   │   └── ommcli/             #   - OMM CLI
│   ├── integrations/           # 第三方集成
│   │   ├── allure_custom/      #   - Allure 报告定制
│   │   ├── jenkins_opt.py      #   - Jenkins 操作
│   │   ├── ssh_mgr.py          #   - SSH 管理
│   │   └── retry.py            #   - 重试机制
│   ├── models/                 # 数据模型
│   │   ├── conf.py             #   - 配置模型
│   │   ├── engine.py           #   - 引擎模型
│   │   ├── result.py           #   - 结果模型
│   │   └── testcase.py         #   - 用例模型
│   ├── reporter/               # 报告
│   │   └── log_to_html/        #   - 日志转 HTML
│   ├── notification/           # 通知
│   │   ├── mail.py             #   - 邮件
│   │   └── qw_chat.py          #   - 企业微信
│   ├── database/               # 数据库支持
│   │   ├── mysql.py            #   - MySQL
│   │   └── sqlite.py           #   - SQLite
│   └── utils/                  # 工具
│       ├── util.py
│       ├── file_helper.py
│       └── retry.py            #   重试装饰器
├── demo/                       # 演示项目（MinIO）
├── tests/                      # 框架自身测试
├── setup.py                    # 安装配置
└── requirements.txt            # 依赖清单
```

---

## 依赖概览

| 依赖 | 用途 |
|------|------|
| pytest | 测试框架 |
| requests | HTTP 客户端 |
| selenium | Web UI 自动化 |
| Appium-Python-Client | APP 自动化 |
| loguru | 日志 |
| allure-pytest | Allure 报告集成 |
| PyMySQL / SQLAlchemy | 数据库 |
| paramiko / scp | SSH 远程操作 |
| typer | CLI 命令行 |
| PyYAML | YAML 用例解析 |
| Faker | 测试数据生成 |
| xmindparser | XMind 用例导入 |
| Jinja2 | HTML 报告模板 |
