# shelltest-FW **Repository Path**: WDM902/shelltest-framework ## Basic Information - **Project Name**: shelltest-FW - **Description**: No description available - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-21 - **Last Updated**: 2026-03-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ShellTestFW ## 目录结构 ```text framework/ ├── bin/run.sh # 执行入口 ├── lib/ # 核心库(由 lib/common.sh 聚合 source) │ ├── common.sh # 唯一入口:测试用例只 source 本文件即可 │ ├── log.sh │ ├── assert.sh │ ├── ssh.sh │ ├── system.sh │ ├── network.sh │ ├── test_helpers.sh # Skip/临时目录/等待/文件读写等 │ ├── disk.sh │ ├── process.sh │ ├── service.sh │ ├── package.sh │ ├── config.sh │ ├── util.sh │ ├── compat.sh # 数字校验、注释行判断(避免 [[ =~ ]] 差异) │ ├── exec.sh │ ├── advanced.sh │ └── report.sh # 仅 run.sh 引用:生成 HTML/MD 报告 ├── testcases/ # 测试套件(每子目录一套 cases.list) │ ├── network/ │ ├── disk/ │ └── system/ ├── conf/ │ └── env.conf.example # 复制为 env.conf ├── logs/ # 预留运行日志目录 └── reports/ # 运行结果与 report.html / report.md / report.pdf ``` ## 稳定性与容错 - `run.sh`:`mkdir`/`日志写入`失败会报错并尽量继续或中止;`-t` 非法时回退默认超时;`CASE_SHOULD_RETRY` 在日志不可读时仍按策略重试;`list_suites` 按行读取避免套件名含空格被拆断。 - `common.sh`:校验 `OET_PATH/lib` 存在后再加载其余库。 - `util.sh`:`WITH_TIMEOUT` 对秒数做校验;无 `timeout` 命令时给出警告并直接执行命令。 - `exec.sh`:捕获 stdout/stderr 时 `cat` 失败不导致脚本崩溃。 - `assert.sh`:`CHECK_RESULT` 的 `mode` 非法时回退为 0;`CASE_RESULT` 对未设置 `exec_result` 使用安全默认值。 - `report.sh`:汇总数字与耗时计算带默认值/校验,避免未定义变量破坏报告生成。 ## 运行环境(发行版兼容) - **Shell**:建议 **Bash ≥ 3.2**(多数 Linux 默认 `/bin/bash`)。 - **`lib/compat.sh`**:用 `case` + `sed` 做「纯数字」「注释/空行」判断,避免依赖 `[[ =~ ]]`(不同 Bash 版本与 `LC_ALL` 下行为可能不一致)。 - **系统识别**:`GET_OS_TYPE` / `GET_OS_VERSION` 在无 `/etc/os-release` 时(如旧 **Debian**)回退 **`/etc/debian_version`**;**openEuler** / **RHEL 系** 通过 `os-release` 或 **`/etc/openEuler-release`** 等识别。 - **磁盘**:`_GET_ROOT_SOURCE` 在无 GNU `df --output` 时回退 **`df -P`**(POSIX)。 - 目标场景:**CentOS**、**openEuler(欧拉)**、**Debian 6 / 8 / 10** 及更新版本;极简环境若缺少 `timeout`/`mktemp` 等,框架会降级或告警,而非直接崩溃。 ## 快速运行 在 Bash 环境下: ```bash cd framework bash bin/run.sh -l bash bin/run.sh -f system bash bin/run.sh -a ``` ## 编写用例 ```bash #!/usr/bin/env bash export OET_PATH=$(cd "$(dirname "$0")/../.." && pwd) # 按用例所在套件深度调整 ../.. source "${OET_PATH}/lib/common.sh" function run_test() { RUN_AND_CHECK 0 true } main "$@" ``` ## 命令执行(`lib/exec.sh`) - `RUN_CMD ls /`:执行命令并捕获退出码与 stdout/stderr(写入 `STF_LAST_CMD_*`) - `RUN_CMD_WITH_TIMEOUT 5 sleep 10`:带超时(依赖系统 `timeout` 时生效) - `RUN_CMD_RETRY 3 curl …`:最多重试 N 次,间隔 `STF_CMD_RETRY_INTERVAL`(默认 1 秒) - `GET_EXIT_CODE` / `GET_STDOUT` / `GET_STDERR`:读取最近一次 `RUN_CMD*` 的结果(输出到标准输出,便于 `CHECK_RESULT "$(GET_EXIT_CODE)" 0`) ## 断言(`lib/assert.sh`) - **`CHECK_RESULT`**:底层比对;另有 **`RUN_AND_CHECK`**、**`ASSERT_CMD`** - 基础:**`ASSERT_EQUAL` / `ASSERT_NOT_EQUAL`**、**`ASSERT_CONTAINS` / `ASSERT_NOT_CONTAINS`**、**`ASSERT_FILE_EXIST` / `ASSERT_FILE_NOT_EXIST`**、**`ASSERT_CMD_SUCCESS` / `ASSERT_CMD_FAIL`**、**`ASSERT_GT` / `ASSERT_LT`**(`awk`)。失败时累计 **`exec_result`** **扩展(对齐常见 xUnit/pytest 场景):** | 函数 | 含义 | |------|------| | `ASSERT_GE` / `ASSERT_LE` | 数值 `>=` / `<=` | | `ASSERT_EMPTY` / `ASSERT_NOT_EMPTY` | 字符串去空白后是否为空 | | `ASSERT_MATCH` | 固定子串包含(语义同 `ASSERT_CONTAINS`,名称更直观) | | `ASSERT_REGEX` | 整段字符串是否匹配 **ERE**(`grep -E`) | | `ASSERT_FILE_CONTAINS` | 文件中是否含固定子串(`grep -F`) | | `ASSERT_FILE_LINE_MATCH` | 文件中是否至少一行匹配 ERE | | `ASSERT_FILES_EQUAL` | 两普通文件内容一致(`cmp -s`) | ## 测试辅助(`lib/test_helpers.sh`,对标 pytest skip/tmp、Robot Wait) | 类别 | 函数 | 说明 | |------|------|------| | 跳过 | `STF_SKIP [reason]` | 退出码 **255**,与运行器「跳过」一致 | | | `STF_SKIP_IF cmd…` / `STF_SKIP_UNLESS cmd…` | 条件满足/不满足时跳过 | | 临时资源 | `STF_MKTEMP_DIR` / `STF_MKTEMP_FILE` | 临时目录与文件路径 | | 轮询 | `WAIT_FOR_CMD T I cmd…` | 每隔 `I` 秒重试命令,最长 `T` 秒 | | | `WAIT_FOR_FILE T I path` | 直到路径存在 | | | `WAIT_FOR_PORT host port [T [I]]` | TCP 端口可连(依赖 `PORT_CHECK`) | | 文件 | `READ_FILE` / `WRITE_FILE` / `FILE_APPEND` | 读全文、覆盖写、追加 | | | `FILE_LINE_COUNT` / `FILE_SIZE_BYTES` | 行数、字节数 | | 字符串 | `STF_STR_TRIM` / `STF_STR_EMPTY` | 去空白、是否空 | | 环境 | `STF_ENV_PUSH` / `STF_ENV_POP` | 保存并恢复单个环境变量(仅 `[a-zA-Z0-9_]` 名) | 写用例时优先组合 **`RUN_CMD` + `ASSERT_*` + `STF_SKIP_*` + `WAIT_FOR_*`**,可减少手写 `grep`/`while`/`mktemp` 的重复与笔误。 ## 高级能力(`lib/advanced.sh`) - **`RUN_PARALLEL `**:最多并发 `n` 条子任务;文件每行一条命令,由 `bash -c` 执行;任一失败则返回 1 - **`TIMEOUT_RUN [args…]`**:封装 `WITH_TIMEOUT`(无 `timeout` 命令时不限时) - **`RETRY [args…]`**:封装 `RUN_CMD_RETRY` - **`MOCK_CMD `** / **`MOCK_RESET`**:在临时目录生成同名脚本并插到 `PATH` 前(弱实现,仅适合简单输出);`MOCK_RESET` 恢复 `PATH` 并删除临时目录 ## 套件钩子(`bin/run.sh` + 可选 `suite.sh`) 若存在 **`testcases//suite.sh`**,运行器会先 `source` 再执行用例。可在其中定义(均为可选): - **`BEFORE_ALL`**:该套件第一个用例前执行一次;失败则中止套件(exit 1) - **`AFTER_ALL`**:套件全部用例结束后执行(含 `-r` 指定用例未找到时仍会调用,便于收尾) - **`BEFORE_EACH `** / **`AFTER_EACH `**:每个用例前后各执行一次 ## SSH / SCP(`lib/ssh.sh`) - 底层:`SSH_CMD`、`SSH_SCP_PUT` / `SSH_SCP_GET`(参数顺序见源码注释) - 便捷(大写):`SSH_EXEC host user pass "cmd" [port] [timeout]` → 转 `SSH_CMD` - `SSH_EXEC_BG host user pass "cmd" [port] [timeout]`:远端 `nohup` 后台执行 - `SCP_TO local host remote_path …`、`SCP_FROM host remote_path local …`:封装上传/下载 - `SSH_CHECK_ALIVE host [port] [user] [timeout]`:探测 SSH;失败时尝试 `ssh-keyscan` 写入 `~/.ssh/known_hosts` 后重试一次 ## 配置(远端节点) ```bash cp conf/env.conf.example conf/env.conf # 编辑 NODE1_IPV4 / NODE1_SSH_PORT / NODE1_USER / NODE1_PASSWORD ``` 默认 `LOAD_CONF` 读取 `conf/env.conf`。 - `CONFIG_SET `:写入 `KEY=%q` 形式(支持空格);已存在同名键则替换行 - `CONFIG_GET `:输出值(含 `export KEY=`);未找到返回 1 - `CONFIG_DEL `:删除匹配行 - `CONFIG_BACKUP ` / `CONFIG_RESTORE `:与同目录 `${STF_CONFIG_BACKUP_EXT}`(默认 `.stf.bak`)互拷 ## 系统信息(`lib/system.sh`) - `GET_OS_TYPE`:粗分类 `debian` / `centos`(含 RHEL 系等)/ `fedora` / `suse` / `alpine` / `arch` / `other` / `unknown` - `GET_OS_VERSION`:`VERSION_ID` 或 `lsb_release -rs` - `GET_KERNEL_VERSION` / `GET_ARCH`:`uname` 内核与架构 - `GET_HOSTNAME`、`GET_UPTIME`、`GET_LOAD`、`GET_MEMORY_INFO` - `GET_CPU_SUMMARY`、`GET_DISK_ROOT`(一行摘要,供报告等使用) ## 测试报告(`reports/report.html`) 由 `bin/run.sh` 在跑完用例后生成,风格参考 Robot Framework 等 HTML 报告: - **顶部**:总用例数、Pass/Fail/Skip、总耗时(近似) - **Run metadata**:测试开始/结束时间、主机名、`PRETTY_NAME` 与 OS 类型/版本、内核、架构、CPU、`load`、根分区 `df`、uptime、内存(`free -h` 或 `/proc/meminfo`) - **按套件**:每个用例为可展开 `
`(失败/跳过默认展开),展示 exit、重试次数、单次耗时、**各 attempt 的日志路径**(相对 `reports/`)及 **日志正文**(每 attempt 最多嵌入末尾 8000 行) `report.md` 同步包含摘要表与元数据;若安装 `pandoc` 或 `wkhtmltopdf` 可生成 `report.pdf`。 ## 网络(`lib/network.sh`) - `GET_ALL_INTERFACES`:列出全部接口名(优先 `/sys/class/net`) - `GET_INTERFACE_IP` / `GET_NIC_IP `:IPv4(global) - `SET_IP [prefix|/cidr]`、`DEL_IP [addr/cidr]`(无 addr 时 flush 该口 IPv4) - `INTERFACE_UP` / `INTERFACE_DOWN` - `PING_TEST `(`STF_PING_COUNT`、`STF_PING_TIMEOUT_SEC`) - `PORT_CHECK `(`STF_PORT_CHECK_TIMEOUT`;`timeout`+`/dev/tcp` 或 `nc`) - `GET_ROUTE […]`、`ADD_ROUTE …`、`DEL_ROUTE …`(透传 `ip route`) ## 进程(`lib/process.sh`) - `GET_PID `:无空格时先试 `pgrep -x`,再 `pgrep` / `pgrep -f`;含空格则按命令行用 `pgrep -f` - `KILL_PROCESS [signal]`(默认 `TERM`) - `CHECK_PROCESS_EXIST ` - `GET_PROCESS_CPU `:CPU%(`ps`) - `GET_PROCESS_MEM `:RSS,单位 kB(`/proc//status` 或 `ps`) - 另有:`PROCESS_PID_BY_PATTERN`(`pgrep -f`)、`PROCESS_WAIT_EXIT`、`PROCESS_KILL_TREE`