已开启
add: mugen-case-genarator skill #145
xu_yishen创建于 7月2日
add: mugen-case-genarator skill #145
已开启
xu_yishen创建于 7月2日
6 个文件变更+495-0
Askills/mugen-case-generator/REFERENCE.md+193-0
@@ -0,0 +1,193 @@
1+# mugen 用例生成 —— 参考手册
2+ 
3+[SKILL.md](SKILL.md) 背后的详细规则、踩坑和模式。规范的权威来源是 mugen 仓库里的
4+`doc/测试用例检视规范.md`。CI 门禁对改动的 `.sh` 文件跑 **ShellCheck 0.7.2**,任何非 `info`
5+级别的告警都会判失败。
6+ 
7+可直接复制的骨架在 [templates/](templates/):`case_template.sh`(已通过 `scripts/verify_case.sh`
8+的用例骨架)、`suite_common_lib_template.sh`(套件公共库)、`suite2cases_template.json`(套件
9+注册)。下面的说明解释这些骨架背后的规则。
10+ 
11+## 1. 头部(精确格式)
12+ 
13+```
14+#!/usr/bin/bash
15+ 
16+# Copyright (c) <年份>. Huawei Technologies Co.,Ltd.ALL rights reserved.
S
SSPYFAMILY7月5日

社区文档建议以社区来署名 # Copyright (c) <年份> openEuler Community. All rights reserved.

likedislike
17+# This program is licensed under Mulan PSL v2.
18+# You can use it according to the terms and conditions of the Mulan PSL v2.
19+# http://license.coscl.org.cn/MulanPSL2
20+# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
21+# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
22+# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
23+# See the Mulan PSL v2 for more details.
24+ 
25+# #############################################
26+# @Author : <姓名>
27+# @Contact : <邮箱>
28+# @Date : <YYYY/MM/DD>
29+# @License : Mulan PSL v2
30+# @Desc : <英文描述>
31+# #############################################
32+```
33+ 
34+- `<年份>` 必须是**当前年份**(§2.4)。
35+- `@Desc` 和所有注释**全英文**(§2.1)。
36+- 套件公共库文件的 `@Desc` 例如 `common function library for the <套件> test suite`
37+ 
38+## 2. source 行
39+ 
40+- 每个用例**只有一行** `source`
41+- 必须用 `${OET_PATH}` 形式:`source "${OET_PATH}"/libs/locallibs/common_lib.sh`
42+ (mugen 运行时把 `OET_PATH` 设为仓库根,并 `pushd` 进用例目录,所以相对路径 `../common/...`
43+ *执行*时没问题;但 ShellCheck 是从仓库根跑的,跟不进去 → `SC1091: openBinaryFile: does not
44+ exist` → CI 失败。)
45+- 如果套件有公共库,**用例**只 source 套件库
46+ (`source "${OET_PATH}"/testcases/<域>/<套件>/common/<套件>_common.sh`),套件库内部去 source
47+ `common_lib.sh`。每个文件一行 source。
48+ 
49+## 3. 阶段结构 & LOG_INFO
50+ 
51+```
52+function pre_test() { LOG_INFO "Start environmental preparation."; ...; LOG_INFO "End of environmental preparation!"; }
53+function run_test() { LOG_INFO "Start testing..."; ...; LOG_INFO "Finish test!"; }
54+function post_test() { LOG_INFO "start environment cleanup."; ...; LOG_INFO "Finish environment cleanup!"; }
55+main "$@"
56+```
57+ 
58+- 确无必要时可省略 `config_params`/`pre_test`/`post_test`(§2.4)。
59+- **正好六条 LOG_INFO**(每阶段首尾各一)。**阶段体内不许写 LOG_INFO**——上下文写到 `CHECK_RESULT`
60+ 的消息里。
61+ 
62+## 4. CHECK_RESULT
63+ 
64+- 签名:`CHECK_RESULT <实际> <期望> <模式> "<消息>"`(4 个参数)。
65+ - `模式 0`:`实际 == 期望` 算通过。`模式 1`:`实际 != 期望` 算通过。
66+- `run_test` 里每个测试命令都是一个测试点 → 后面必须跟 `CHECK_RESULT`**不要**跑一大段命令后才
67+ 一个 CHECK_RESULT。
68+- **pre_test/post_test 里绝对不能有 `CHECK_RESULT`**(§2.4)——从这两个阶段调用的 helper 里也不能有。
69+- 行为:`CHECK_RESULT` **累加**失败到 `exec_result` 并继续,**成功不退出**(只有 `main``run_test`
70+ 之后调用的 `CASE_RESULT` 才退出)。所以多个检查点都会跑到,放进 helper 里也安全。
71+- mugen 看到的退出码:`0`→成功,`255`→跳过,其它→失败。
72+ 
73+### 检查点模式
74+ 
75+- **单个进程启动**:捕获 `$!`、跟踪、验证存活:
76+ ```bash
77+ some_cmd &
78+ local PID
79+ PID=$!
80+ em_track_pid "$PID" # 若套件库提供;否则用本地数组跟踪
81+ kill -0 "$PID"
82+ CHECK_RESULT $? 0 0 "<什么> 进程启动失败"
83+ ```
84+- **循环里批量启动**:把 PID 收进数组,验证至少一个存活(**不要用 `pgrep -f 'pattern'`**——不稳:
85+ bash 可能 exec 掉命令、丢掉关键字,且 `&` 后有竞态):
86+ ```bash
87+ local pids=() p alive=0
88+ for _ in $(seq 1 N); do
89+ some_cmd &
90+ p=$!; pids+=("$p"); em_track_pid "$p"
91+ done
92+ for p in "${pids[@]}"; do kill -0 "$p" 2>/dev/null && { alive=1; break; }; done
93+ [ "$alive" -eq 1 ]
94+ CHECK_RESULT $? 0 0 "<什么> 进程启动失败"
95+ ```
96+- **声明与赋值分开**避免 SC2155:`local x` 换行 `x=$(...)`,不要 `local x=$(...)`
97+ 
98+## 5. SLEEP_WAIT
99+ 
100+-`SLEEP_WAIT <秒>`(来自 common_lib.sh),不要裸 `sleep`。
101+- `SLEEP_WAIT 5` 睡 5 秒;`SLEEP_WAIT 5m` = 5 分钟;`SLEEP_WAIT 5 <cmd>` 带超时跑 cmd。
102+ 
103+## 6. 环境不满足时的跳过
104+ 
105+mugen 的 `main`(`libs/locallibs/common_lib.sh:119-124`)调用 `pre_test`**不看返回值**直接调
106+`run_test`。所以 `pre_test` 里的 `em_check_env || return 1` **拦不住** `run_test`。要真正跳过,在
107+`pre_test` 里用 `exit 255`(EXIT trap 仍会跑 `post_test` 清理;mugen 记为*跳过*):
108+ 
109+```bash
110+function pre_test() {
111+ LOG_INFO "Start environmental preparation."
112+ <环境检查> || exit 255 # 环境不满足就跳过整个用例
113+ ...
114+ LOG_INFO "End of environmental preparation!"
115+}
116+```
117+ 
118+**不要**`run_test` 里再放一遍环境检查——那正是要避免的冗余模式。
119+ 
120+## 7. 套件公共库模式
121+ 
122+复制 [templates/suite_common_lib_template.sh](templates/suite_common_lib_template.sh),把里面的
123+`x_` 前缀改成你套件的前缀。真实例子见 `testcases/cli-test/elasticMem/common/em_common.sh`
124+ 
125+- 库内部 source `common_lib.sh`:`source "${OET_PATH}"/libs/locallibs/common_lib.sh`
126+- 每个用例只 source 这个库(一行)。
127+- helper 按调用阶段分两类:
128+ - **校验类 helper**(在 `run_test` 调用:断言、启服务、写配置)→ 内部 `CHECK_RESULT`,让 helper
129+ 自校验,用例直接调(可传消息:`em_start_service "light start failed"`)。
130+ - **pre/post 类 helper**(备份、停止、恢复、装包)→ `return 0/1`,**绝不 `CHECK_RESULT`**(§2.4)。
131+- 给"日志写文件、不走 journald"的服务做日志断言时,用**行数边界**避免跨用例污染:
132+ ```bash
133+ em_LOG_START=0
134+ em_mark_log() { em_LOG_START=$(wc -l < "$LOG_FILE" 2>/dev/null); em_LOG_START=${em_LOG_START:-0}; }
135+ em_log_window(){ [ -f "$LOG_FILE" ] || return 0; tail -n +$((em_LOG_START + 1)) "$LOG_FILE" 2>/dev/null; }
136+ em_assert_log_contains() {
137+ local pattern=$1 msg=${2:-"expected log not found: $1"}
138+ em_log_window | grep -q -- "$pattern" 2>/dev/null
139+ CHECK_RESULT $? 0 0 "$msg"
140+ }
141+ ```
142+ (`em_mark_log` 在产生日志的动作之前调用,例如 `em_start_service``systemctl restart` 之前。)
143+ 
144+## 8. 便携负载生成器(stress-ng 不可用时)
145+ 
146+openEuler 仓库常缺 `stress-ng`。用便携替代:
147+- **CPU 负载**:`numactl --cpunodebind=0 --membind=0 bash -c '(( end = SECONDS + TMOUT )); while (( SECONDS < end )); do :; done' &`
L
Llinqian03227月2日

numactl非内置 需要提前检查是否安装

likedislike
148+ (超时通过环境变量传给内层 bash;用 `(( ))` 算术不带 `$`,单引号里不会触发 SC2016)。
149+- **内存负载**:`numactl --cpunodebind=0 --membind=0 python3 -c '<mmap+touch+sleep>' <字节数> <超时> &`
150+ (直接用 `&` 启动并捕获 `$!`;**不要**`$(...)` 子 shell 里启动后台进程——它活不过子 shell 退出)。
151+ 
152+## 9. ShellCheck 修复对照表(用代码修,绝不 `# shellcheck disable`)
153+ 
154+| 码 | 含义 | 修法 |
155+|---|---|---|
156+| SC1091 | source 跟不进去(相对路径) | 改用 `${OET_PATH}/...` 绝对路径 → 变 SC1090(info,允许) |
157+| SC2086 | 变量没加引号 | 加引号:`"$VAR"` |
158+| SC2155 | `local x=$(cmd)` 掩盖返回值 | 拆开:`local x` 换行 `x=$(cmd)` |
159+| SC2002 | `cat file \| grep` | `grep pat file` |
160+| SC2010/SC2012 | `ls \| grep` / `ls -d glob` | `find ... -name ...` 或 bash 数组 glob |
161+| SC2126 | `grep \| wc -l` | `grep -c` |
162+| SC2068 | `${arr[@]}` 没引号 | `"${arr[@]}"` |
163+| SC2046 | `$(...)` 没引号 | 加引号 |
164+| SC2034 | 未用变量 | 删掉;若被外部用则 `export` |
165+| SC2016 | 单引号里有 `$` | 改用 `(( ))` 算术(无 `$`)或双引号配 `\$` |
166+| SC2119 | 无参调用带 `$1` 的函数 | 显式传参 |
167+| SC2154 | 引用了被 source 库里的变量 | 内联逻辑,或让 helper 通过调用方能 `kill -0`/读取的方式设置 |
168+ 
169+如果某个告警是真·误报、用代码消不掉,重新审视设计——mugen 的要求是零非 info 告警 + 零 disable 指令。
170+ 
171+## 10. 规范要点清单(§2.4 摘要)
172+ 
173+- 注释英文;年份当前;4 空格缩进;参数/特殊符号前后一个空格。
174+- `grep xxx file`;`test -f file`;不留死代码/未用变量;能归并的语句归并。
175+- 临时文件放 `/tmp`(或在当前路径建临时目录),post_test 里清理。
176+- 每个用例独立(互不依赖、互不影响)。
177+- `DNF_INSTALL "p1 p2"`(多包);`DNF_REMOVE`(不带参,与 DNF_INSTALL 配合)。
178+- `cp -f``mv -rf``userdel -rf`
atomgit-bot
atomgit-botatomgit-bot7月2日

🟡 Medium Priority

变更行:REFERENCE.md 第 178 行,cp -fmv -rfuserdel -rf

mv 命令(GNU coreutils / POSIX)不支持 -r / --recursive 标志——mv 对目录操作本身已经是递归的,无需且不接受 -r。在 GNU/Linux 环境执行 mv -rf src dst 会报错 mv: invalid option -- 'r' 并退出非零。

如果用户按此文档编写 post_test 清理逻辑,实际执行到该行时会导致用例失败。userdel -rfcp -f 都是合法标志组合,唯独 mv -rf 是错误用法。应改为 mv -f

建议:将 mv -rf 改为 mv -f。同时检查 doc/测试用例检视规范.md 原文是否存在同样问题——若原文也有此错误,应一并修正。

改动建议
178
- - `cp -f`、`mv -rf`、`userdel -rf`。
178
+ - `cp -f`、`mv -f`、`userdel -rf`。
应用建议
likedislike
179+- 用框架公共变量/方法(`NODE1_*``DNF_INSTALL``SLEEP_WAIT``CHECK_RESULT`)。
180+- pre_test/post_test 只放预置/清理代码;run_test 只放测试代码;里面不能出现 `python xx` 执行命令。
181+- 取当前路径:`x=$(cd "$(dirname "$0")" || exit 1; pwd)`
182+- 看标准错误输出:`cmd 2>&1 | grep xxx`
183+ 
184+## 11. 运行与校验
185+ 
186+```bash
187+export OET_PATH=/path/to/mugen
188+bash mugen.sh -f <套件> -r <用例> # 单个用例
189+bash mugen.sh -f <套件> # 整个套件
190+```
191+结果在 `results/<套件>/{succeed,failed,skipped}/<用例>`;日志在 `logs/<套件>/<用例>/`
192+退出 `0`→成功,`255`→跳过,其它→失败。声明用例完成前,**必须**`scripts/verify_case.sh <文件>`
193+(静态校验)**和**一次真实 mugen 执行。
Askills/mugen-case-generator/SKILL.md+75-0
@@ -0,0 +1,75 @@
1+---
L
Llinqian03227月2日

缺失顶层README和openai.yaml

likedislike
2+name: mugen-case-generator
3+description: >
L
Llinqian03227月2日

description过长 可以考虑拆分成结构块 并突出关键词

likedislike
4+ 生成和修复 openEuler mugen 测试用例(oe_test_*.sh),使其符合 doc/测试用例检视规范.md 并通过
5+ CI 的 ShellCheck 0.7.2 门禁(只允许 info 级别告警)。覆盖:标准 Copyright/Mulan-PSL-v2 头、
6+ 单个 ${OET_PATH} source 行、pre_test/run_test/post_test 三阶段、六条 LOG_INFO 规则、
7+ CHECK_RESULT 规则、SLEEP_WAIT、套件公共库设计、中文注释改英文(§2.1),以及那些不直观的坑
8+ (mugen 的 main 不会因 pre_test 失败而跳过 run_test;CHECK_RESULT 是累加不退出;进程启动要用
9+ kill-0 验证而非 pgrep)。当用户要写/改/修 mugen 用例、建测试套,或提到 mugen、oe_test_
10+ pre_test/run_test/post_test、CHECK_RESULT、SLEEP_WAIT、DNF_INSTALL,或要修一个过不了 CI
11+ ShellCheck 的 mugen 用例时使用。
12+---
13+ 
14+# mugen 用例生成器
15+ 
16+让 mugen 用例既符合 `doc/测试用例检视规范.md`,又过得了 CI 的 ShellCheck 0.7.2 门禁(只有 `info`
17+级告警允许)。可复制的骨架在 [templates/](templates/);详细规则和踩坑在
18+[REFERENCE.md](REFERENCE.md);用 [scripts/verify_case.sh](scripts/verify_case.sh) 做合规校验。
19+ 
20+## 快速上手
21+ 
22+1. 复制骨架:`cp templates/case_template.sh oe_test_<包名>_<序号>.sh`(新建套件则用
23+ `templates/suite_common_lib_template.sh` + `templates/suite2cases_template.json`)。
24+2. 填掉所有 `<PLACEHOLDER>` / `true` 占位。保留那六条 `LOG_INFO`;`run_test` 里每个测试点后加
25+ `CHECK_RESULT`
26+3. 如果有中文,先翻成英文(见下)。
27+4. 校验:`scripts/verify_case.sh oe_test_<包名>_<序号>.sh` —— 必须 PASS。
28+5. 实跑:`export OET_PATH=<mugen 仓库>; bash mugen.sh -f <套件> -r <用例>`
29+ 
30+## 核心规则(精简版,详见 REFERENCE.md)
31+ 
32+- **头部**:Copyright(当前年份)+ Mulan PSL v2 + `#@Author/@Contact/@Date/@License/@Desc`;**注释全英文**(§2.1)。
33+- **只 source 一次**,写成 `${OET_PATH}/...` 形式。不要相对路径 `../common/...`,不要两行 source。
34+- **三阶段**:`pre_test`(预置)/`run_test`(测试)/`post_test`(清理)+ `main "$@"`
35+- **正好六条 LOG_INFO**:每个阶段的开始和结束各一条。**阶段体内不许再写 LOG_INFO**——上下文放进 `CHECK_RESULT` 的消息里。
36+- **CHECK_RESULT** `<实际> <期望> <模式> "<消息>"`(4 个参数),跟在 `run_test` 里每个测试点后面。**pre/post 里绝对不能有**(§2.4)。
37+- **SLEEP_WAIT**,不要裸 `sleep`。
38+- **ShellCheck**:只允许 `info`(SC1090/SC1091,来自 source 行)。warning/style/error 全部为 0。用代码修,**绝不加 `# shellcheck disable`**
39+- **风格**:4 空格缩进;`grep xxx file`;`test -f file`;不留死代码/未用变量;临时文件放 `/tmp` 并在 post_test 清理;`cp -f`/`mv -rf`/`userdel -rf`;用 `DNF_INSTALL`/`DNF_REMOVE`/`NODE1_*`。
atomgit-bot
atomgit-botatomgit-bot7月2日

🟡 Medium Priority

变更行:SKILL.md 第 39 行,核心规则精简版中列出了 cp -f/mv -rf/userdel -rf

与 REFERENCE.md 第 178 行相同的问题:mv 命令(GNU coreutils / POSIX)不支持 -r 标志。执行 mv -rf src dst 会报 mv: invalid option -- 'r' 并失败。SKILL.md 作为快速上手指南,用户很可能直接复制此处的命令模式到用例中,导致运行时失败。

应改为 mv -f

建议:将 mv -rf 改为 mv -f

改动建议
39
- - **风格**:4 空格缩进;`grep xxx file`;`test -f file`;不留死代码/未用变量;临时文件放 `/tmp` 并在 post_test 清理;`cp -f`/`mv -rf`/`userdel -rf`;用 `DNF_INSTALL`/`DNF_REMOVE`/`NODE1_*`。
39
+ - **风格**:4 空格缩进;`grep xxx file`;`test -f file`;不留死代码/未用变量;临时文件放 `/tmp` 并在 post_test 清理;`cp -f`/`mv -f`/`userdel -rf`;用 `DNF_INSTALL`/`DNF_REMOVE`/`NODE1_*`。
应用建议
likedislike
40+ 
41+## 中文改英文(§2.1)
42+ 
43+规范要求**所有注释和描述用英文**。如果用例(或用户给的草稿)里有中文,把**全部**中文翻成英文——
44+`@Desc`、行内 `#` 注释、`LOG_INFO` 消息、`CHECK_RESULT` 消息——保留语义、不改代码逻辑。你本身是
45+LLM,直接逐行翻译即可。
46+ 
47+```bash
48+grep -nP '[\x{4e00}-\x{9fff}]' <文件> # 找出所有含中文的行
49+# 逐行翻成英文,然后:
50+scripts/verify_case.sh <文件> # 确认 "no CJK"
51+```
52+ 
53+## 校验(两步都做)
54+ 
55+```bash
56+scripts/verify_case.sh <文件> # 静态校验:bash -n、shellcheck 仅 info、
57+ # 单 source 行、六条 LOG_INFO、pre/post 无
58+ # CHECK_RESULT、无中文、年份当前……
59+export OET_PATH=<mugen 仓库>
60+bash mugen.sh -f <套件> -r <用例> # 真跑(0=成功,255=跳过,其它=失败)
61+```
62+ 
63+## 最常踩的坑(完整清单见 REFERENCE.md)
64+ 
65+- **pre_test 的环境守卫必须 `exit 255`**——mugen 的 `main` 不看 `pre_test` 返回值,照样跑 `run_test`;`return 1` 会判 *失败*,`exit 255` 才判 *跳过*(且 post_test 仍会经 EXIT trap 跑清理)。
66+- **`CHECK_RESULT` 是累加的,成功不退出**——可以放心放进 helper 里;多个检查点都会跑到。
67+- **进程启动用 `kill -0 "$PID"` 验证,不要用 pgrep**——pgrep 不稳(bash 可能 exec 掉关键字;`&` 后有竞态)。
68+- **写文件的服务的日志断言**:用行数边界(`wc -l` 在前,`tail -n +N` 在后)避免跨用例污染——见 [REFERENCE.md](REFERENCE.md#7-套件公共库模式)。
69+- **`stress-ng` 常缺失**:用便携负载(`numactl ... bash -c` / `python3 mmap`)。
70+ 
71+## 套件公共库
72+ 
73+多个用例共享逻辑时,用 [templates/suite_common_lib_template.sh](templates/suite_common_lib_template.sh):
74+库内部 source `common_lib.sh`;校验类 helper 自带 `CHECK_RESULT`;pre/post 类 helper 只 `return 0/1`
75+用例只 source 这个库(一行)。
Askills/mugen-case-generator/scripts/verify_case.sh+81-0
@@ -0,0 +1,81 @@
1+#!/usr/bin/bash
2+# 校验 mugen 测试用例是否符合规范 + CI ShellCheck 门禁。
3+# 用法:verify_case.sh <用例.sh> (可设 OET_PATH 指向 mugen 仓库以提供上下文)
4+# 任一检查不过则非 0 退出。
5+ 
L
Llinqian03227月2日

建议加上用例名称的检查 oe_test_[_].sh 模式

likedislike
6+set -u
7+f="${1:-}"
8+[ -n "$f" ] || { echo "用法: $0 <用例.sh>"; exit 2; }
9+[ -f "$f" ] || { echo "失败:文件不存在: $f"; exit 2; }
10+ 
11+fail=0
12+say() { printf '%s\n' "$*"; }
13+warn() { printf ' ✗ %s\n' "$*"; fail=1; }
14+ok() { printf ' ✓ %s\n' "$*"; }
15+ 
16+say "=== $f ==="
17+ 
18+# 1. bash 语法
19+if bash -n "$f"; then ok "bash -n 语法"; else warn "bash -n 语法失败"; fi
20+ 
21+# 2. ShellCheck 0.7.2 仅 info(若已安装)
22+if command -v shellcheck >/dev/null 2>&1; then
23+ bad=$(shellcheck --format=checkstyle "$f" 2>/dev/null | grep -oE "severity='[a-z]+'" | grep -v "info" | sort -u | tr '\n' ' ')
24+ if [ -z "$bad" ]; then ok "shellcheck:仅 info"; else warn "shellcheck 有非 info 告警: $bad"; shellcheck "$f" 2>&1 | grep -E 'SC[0-9]' | grep -vE 'SC1091|SC1090' | head -10; fi
25+else
26+ say " (未安装 shellcheck——跳过 lint)"
27+fi
28+ 
29+# 3. 只有一行 source
30+n=$(grep -c '^source ' "$f")
31+[ "$n" -eq 1 ] && ok "单 source 行($n)" || warn "应只有 1 行 source,实际 $n"
32+ 
33+# 4. source 用 ${OET_PATH}
34+grep -q '^source "${OET_PATH}"' "$f" && ok 'source 用 ${OET_PATH} 形式' || warn 'source 不是 ${OET_PATH}/... 形式'
35+ 
36+# 5. 正好六条 LOG_INFO
37+n=$(grep -c 'LOG_INFO' "$f")
38+[ "$n" -eq 6 ] && ok "六条 LOG_INFO($n)" || warn "应为 6 条 LOG_INFO(pre/run/post 各首尾),实际 $n"
39+ 
40+# 6. pre_test / post_test 里不能有 CHECK_RESULT
41+pt=$(sed -n '/function pre_test()/,/function run_test()/p' "$f")
42+po=$(sed -n '/function post_test()/,/^main /p' "$f")
43+echo "$pt" | grep -q 'CHECK_RESULT' && warn "pre_test 里有 CHECK_RESULT(§2.4 禁止)"
44+echo "$po" | grep -q 'CHECK_RESULT' && warn "post_test 里有 CHECK_RESULT(§2.4 禁止)"
45+{ echo "$pt" | grep -q 'CHECK_RESULT' || echo "$po" | grep -q 'CHECK_RESULT'; } || ok "pre/post 无 CHECK_RESULT"
46+ 
47+# 7. 不能有 # shellcheck disable 指令
48+n=$(grep -c '# shellcheck disable' "$f")
49+[ "$n" -eq 0 ] && ok "无 shellcheck disable 指令" || warn "发现 $n 处 '# shellcheck disable'——应改用代码修复"
50+ 
51+# 8. 注释不能有中文(§2.1 要求全英文)
52+if grep -nP '[\x{4e00}-\x{9fff}]' "$f" >/dev/null 2>&1; then
53+ warn "存在非英文(中文)字符——注释必须英文(§2.1)"
54+ grep -nP '[\x{4e00}-\x{9fff}]' "$f" | head -5
55+else
56+ ok "无中文(注释为英文)"
57+fi
58+ 
59+# 9. 不能有裸 sleep(用 SLEEP_WAIT)
60+n=$(grep -cE '(^|[^_])sleep [0-9]' "$f")
61+[ "$n" -eq 0 ] && ok "无裸 'sleep N'(用 SLEEP_WAIT)" || warn "发现 $n 处裸 'sleep N'——改用 SLEEP_WAIT"
62+ 
63+# 10. 头部齐全
64+head -1 "$f" | grep -q '^#!/usr/bin/bash' && ok "shebang" || warn "缺 #!/usr/bin/bash"
65+grep -q 'Copyright (c)' "$f" && ok "Copyright 行" || warn "缺 Copyright 行"
66+grep -q 'Mulan PSL v2' "$f" && ok "Mulan PSL v2 许可" || warn "缺 Mulan PSL v2 块"
67+grep -q '#@Author\|# @Author' "$f" && ok "@Author/@Desc 头" || warn "缺 @Author/@Desc 头"
68+yr=$(grep -oE 'Copyright \(c\) [0-9]{4}' "$f" | grep -oE '[0-9]{4}')
69+cur=$(date +%Y)
70+[ "$yr" = "$cur" ] && ok "版权年份当前($yr)" || warn "版权年份 '$yr'(应为 $cur)"
71+ 
72+# 11. 末尾 main "$@"
73+grep -q '^main "\$@"' "$f" && ok 'main "$@"' || warn '缺 main "$@"'
74+ 
75+# 12. 三阶段齐全
76+for fn in pre_test run_test post_test; do
77+ grep -q "function $fn()" "$f" && ok "$fn 已定义" || warn "$fn 未定义"
78+done
79+ 
80+say "---"
81+[ "$fail" -eq 0 ] && { say "通过:$f 合规"; exit 0; } || { say "失败:$f 存在上述问题"; exit 1; }
Askills/mugen-case-generator/templates/case_template.sh+49-0
@@ -0,0 +1,49 @@
1+#!/usr/bin/bash
2+#
3+# Canonical mugen test-case skeleton. Copy this file, rename to
4+# oe_test_<pkg>[_<num>|_<cmd>].sh, and replace every <PLACEHOLDER> / `true` marker.
5+# After editing, run: scripts/verify_case.sh <your_file>
6+ 
7+# Copyright (c) 2026. Huawei Technologies Co.,Ltd.ALL rights reserved.
S
SSPYFAMILY7月5日

社区文档建议以社区来署名 # Copyright (c) <年份> openEuler Community. All rights reserved.

likedislike
8+# This program is licensed under Mulan PSL v2.
9+# You can use it according to the terms and conditions of the Mulan PSL v2.
10+# http://license.coscl.org.cn/MulanPSL2
11+# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
12+# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
13+# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
14+# See the Mulan PSL v2 for more details.
15+ 
16+# #############################################
17+# @Author : <author name>
18+# @Contact : <author email>
19+# @Date : <YYYY/MM/DD>
20+# @License : Mulan PSL v2
21+# @Desc : <one-line English description of what this case verifies>
22+# #############################################
23+ 
24+source "${OET_PATH}"/libs/locallibs/common_lib.sh
25+ 
26+function pre_test() {
27+ LOG_INFO "Start environmental preparation."
28+ # install packages under test: DNF_INSTALL "<pkg1> <pkg2>"
29+ # create any temp files under /tmp; back up files you will modify
30+ # if the case needs a special environment, skip cleanly: <check> || exit 255
31+ LOG_INFO "End of environmental preparation!"
32+}
33+ 
34+function run_test() {
35+ LOG_INFO "Start testing..."
36+ # replace: run the command/feature under test, then CHECK_RESULT every test point
37+ true
38+ CHECK_RESULT $? 0 0 "<expected outcome message>"
39+ # more test points, each followed by its own CHECK_RESULT ...
40+ LOG_INFO "Finish test!"
41+}
42+ 
43+function post_test() {
44+ LOG_INFO "start environment cleanup."
45+ # restore backed-up files; DNF_REMOVE; rm temp files
46+ LOG_INFO "Finish environment cleanup!"
47+}
48+ 
49+main "$@"
Askills/mugen-case-generator/templates/suite2cases_template.json+7-0
@@ -0,0 +1,7 @@
1+{
2+ "path": "$OET_PATH/testcases/cli-test/<suite>",
3+ "cases": [
4+ {"name": "oe_test_<pkg>_001"},
5+ {"name": "oe_test_<pkg>_002"}
6+ ]
7+}
Askills/mugen-case-generator/templates/suite_common_lib_template.sh+90-0
@@ -0,0 +1,90 @@
1+#!/usr/bin/bash
2+#
3+# Suite common-library skeleton (e.g. testcases/cli-test/<suite>/common/<suite>_common.sh).
4+# Use when several cases share setup/assertion helpers. Each case then sources ONLY this
5+# lib (one source line): source "${OET_PATH}"/testcases/cli-test/<suite>/common/<suite>_common.sh
6+#
7+# This template uses the prefix "x_" — rename every x_ to your suite's prefix (e.g. em_).
8+#
9+# Rules:
10+# - this lib sources common_lib.sh internally (so cases source only this lib, once).
11+# - verification helpers (assert / start-service / write-config) call CHECK_RESULT internally.
12+# - helpers called from pre_test/post_test (backup/stop/restore/require-pkg) return 0/1, NEVER CHECK_RESULT.
13+ 
14+# Copyright (c) 2026. Huawei Technologies Co.,Ltd.ALL rights reserved.
S
SSPYFAMILY7月5日

社区文档建议以社区来署名 # Copyright (c) <年份> openEuler Community. All rights reserved.

likedislike
15+# This program is licensed under Mulan PSL v2.
16+# You can use it according to the terms and conditions of the Mulan PSL v2.
17+# http://license.coscl.org.cn/MulanPSL2
18+# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
19+# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
20+# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
21+# See the Mulan PSL v2 for more details.
22+ 
23+# #############################################
24+# @Author : <author name>
25+# @Contact : <author email>
26+# @Date : <YYYY/MM/DD>
27+# @License : Mulan PSL v2
28+# @Desc : common function library for the <suite> test suite
29+# #############################################
30+ 
31+source "${OET_PATH}"/libs/locallibs/common_lib.sh
32+ 
33+# shared constants used by the cases
34+X_CONFIG="/etc/x.conf"
35+X_LOG_FILE="/var/log/x/x.log"
36+X_SERVICE="x"
37+ 
38+# --- helpers used from pre_test / post_test (return 0/1, no CHECK_RESULT) ---
39+x_backup_config() {
40+ test -f "$X_CONFIG" && cp -fp "$X_CONFIG" "$X_CONFIG.mugen_bak"
41+}
42+ 
43+x_restore_config() {
44+ test -f "$X_CONFIG.mugen_bak" && cp -fp "$X_CONFIG.mugen_bak" "$X_CONFIG" 2>/dev/null && rm -f "$X_CONFIG.mugen_bak"
45+}
46+ 
47+x_stop_service() {
48+ systemctl stop "$X_SERVICE" 2>/dev/null
49+ SLEEP_WAIT 2
50+}
51+ 
52+# --- verification helpers (called from run_test; CHECK_RESULT internally) ---
53+ 
54+# Write the config; verify the write succeeded.
55+x_write_config() {
56+ cat > "$X_CONFIG" << EOF
57+# config lines here
58+EOF
59+ CHECK_RESULT $? 0 0 "failed to write $X_SERVICE config"
60+}
61+ 
62+# Start the service and verify it is active. Accepts an optional message.
63+x_start_service() {
64+ local msg=${1:-"$X_SERVICE service start failed"}
65+ systemctl restart "$X_SERVICE" 2>/dev/null
66+ SLEEP_WAIT 3
67+ systemctl is-active "$X_SERVICE" --quiet
68+ CHECK_RESULT $? 0 0 "$msg"
69+}
70+ 
71+# Log-window assertion: bound by a line count so cases don't see each other's logs.
72+# x_LOG_START is set by x_mark_log right before the action that produces the log.
73+x_LOG_START=0
74+x_mark_log() { x_LOG_START=$(wc -l < "$X_LOG_FILE" 2>/dev/null); x_LOG_START=${x_LOG_START:-0}; }
75+x_log_window(){ test -f "$X_LOG_FILE" || return 0; tail -n +$((x_LOG_START + 1)) "$X_LOG_FILE" 2>/dev/null; }
76+ 
77+x_assert_log_contains() {
78+ local pattern=$1 msg=${2:-"expected log not found: $1"}
79+ x_log_window | grep -q -- "$pattern" 2>/dev/null
80+ CHECK_RESULT $? 0 0 "$msg"
81+}
82+ 
83+x_assert_not_log_contains() {
84+ local pattern=$1 msg=${2:-"unexpected log found: $1"}
atomgit-bot
atomgit-botatomgit-bot7月2日

🟡 Medium Priority

变更行:suite_common_lib_template.sh 第 84 行。

函数 x_assert_not_log_contains 的语义是"断言日志中不包含指定模式"。当模式被匹配到时(grep 成功,退出 0),进入 if 分支执行 CHECK_RESULT 1 0 0 "$msg",即断言失败——此时应报告"意外发现了不应存在的日志"。

但第 84 行的默认消息是 "expected log not found: $1"("期望的日志未找到"),这是 x_assert_log_contains(正向断言)的语义,与本函数的逆向断言语义完全相反。用户使用此模板且不传自定义消息时,一旦断言触发失败,看到的错误消息会指向相反的方向,严重误导排错。

建议:将默认消息改为 "unexpected log found: $1""log should not contain: $1",与函数名 _assert_not_log_contains 的语义一致。同时检查 REFERENCE.md 第 137 行对应的 em_assert_log_contains 示例中是否存在同样问题(当前示例只展示了正向断言 em_assert_log_contains,未涉及逆向断言,不受影响)。

likedislike
85+ if x_log_window | grep -q -- "$pattern" 2>/dev/null; then
86+ CHECK_RESULT 1 0 0 "$msg"
87+ else
88+ CHECK_RESULT 0 0 0 "$msg"
89+ fi
90+}