Giter VIP home page Giter VIP logo

mugen-riscv's Introduction

mugen

mugen介绍

mugen是openEuler社区开放的测试框架,提供公共配置和方法以便社区开发者进行测试代码的编写和执行

mugen更新说明

  • 优化了mugen框架的入口函数
  • 当前版本添加了对测试套路径和测试用例环境的添加
  • 新增python公共函数

mugen使用教程

安装依赖软件

bash dep_install.sh

配置测试套环境变量

  • 命令执行:bash mugen.sh -c --ip $ip --password $passwd --user $user --port $port
  • 参数说明:
    • ip:测试机的ip地址
    • user:测试机的登录用户,默认为root
    • password: 测试机的登录密码
    • port:测试机ssh登陆端口,默认为22
  • 环境变量文件:./conf/env.json
{
    "NODE": [
        {
            "ID": 1,
            "LOCALTION": "local",
            "MACHINE": "physical",
            "FRAME": "aarch64",
            "NIC": "eth0",
            "MAC": "55:54:00:c8:a9:21",
            "IPV4": "192.168.0.10",
            "USER": "root",
            "PASSWORD": "openEuler12#$",
            "SSH_PORT": 22,
            "BMC_IP": "",
            "BMC_USER": "",
            "BMC_PASSWORD": ""
        },
        {
            "ID": 2,
            "LOCALTION": "remote",
            "MACHINE": "kvm",
            "FRAME": "aarch64",
            "NIC": "eth0",
            "MAC": "55:54:00:c8:a9:22",
            "IPV4": "192.168.0.11",
            "USER": "root",
            "PASSWORD": "openEuler12#$",
            "SSH_PORT": 22,
            "HOST_IP": "",
            "HOST_USER": "",
            "HOST_PASSWORD": ""
            "HOST_SSH_PORT": ""
        }
    ]
}
  • 在用例中的使用:NODE${id}_${LOCALTION}

用例执行

  • 执行所有用例 bash mugen.sh -a
  • 执行指定测试套 bash mugen.sh -f testsuite
  • 执行单条用例 bash mugen.sh -f testsuite -r testcase
  • 日志输出shell脚本的执行过程
bash mugen.sh -a -x 
bash mugen.sh -f testsuite -x
bash mugen.sh -f testsuite -r testcase -x

用例添加

  • 根据模板编写用例脚本(推荐)
source ${OET_PATH}/libs/locallibs/common_lib.sh

# 需要预加载的数据、参数配置
function config_params() {
    LOG_INFO "Start to config params of the case."

    LOG_INFO "No params need to config."

    LOG_INFO "End to config params of the case."
}

# 测试对象、测试需要的工具等安装准备
function pre_test() {
    LOG_INFO "Start to prepare the test environment."

    LOG_INFO "No pkgs need to install."

    LOG_INFO "End to prepare the test environment."
}

# 测试点的执行
function run_test() {
    LOG_INFO "Start to run test."

    # 测试命令:ls
    ls -CZl -all
    CHECK_RESULT 0

    # 测试/目录下是否存在proc|usr|roor|var|sys|etc|boot|dev目录
    CHECK_RESULT "$(ls / | grep -cE 'proc|usr|roor|var|sys|etc|boot|dev')" 7

    LOG_INFO "End to run test."
}

# 后置处理,恢复测试环境
function post_test() {
    LOG_INFO "Start to restore the test environment."

    LOG_INFO "Nothing to do."

    LOG_INFO "End to restore the test environment."
}

main "$@"
  • 单纯的shell脚本或python脚本,通过脚本执行的返回码判断用例是否成功。
    • 可参考样例:testsuite测试套下用例oe_test_casename_02和oe_test_casename_03

suite2cases中json文件的写法

  • 文件名为测试套名,文件后缀.json
  • 文件内容说明:

框架的公共函数

  • 如何加载到用例中,以供调用
# bash
source ${OET_PATH}/libs/locallibs/common_lib.sh

# python
import os, sys, subprocess

LIBS_PATH = os.environ.get("OET_PATH") + "/libs/locallibs"
sys.path.append(LIBS_PATH)
import xxx
  • 公共函数
    • 日志打印
    # bash 
    LOG_INFO "$message"
    LOG_WARN "$message"
    LOG_DEBUG "$message"
    LOG_ERROR "$message"
    # python
    import mugen_log
    mugen_log.logging(level, message) # level:INFO,WARN,DEBUG,ERROR;message:日志输出
    
    • 结果检查
    # bash
    CHECK_RESULT $1 $2 $3 $4
    # $1:测试点的返回结果
    # $2:预期结果
    # $3:对比模式,0:返回结果和预期结果相对;1:返回结果和预期结果不等
    # $4:发现问题,日志输出
    
    • rpm包安装卸载
    # bash
    ## func 1
    DNF_INSTALL "vim bc" "$node_id"
    DNF_REMOVE "$node_id" "jq" "$mode"
    
    # mode:默认为0,会删除用例中安装的包,当为非0时,则只卸载当软件包
    # python
    import rpm_manage
    tpmfile = rpm_manage.rpm_install(pkgs, node, tmpfile)
    rpm_manage.rpm_remove(node, pkgs, tmpfile)
    
    • 远程命令执行
    # bash
    ## func 1
    SSH_CMD "$cmd" $remote_ip $remote_password $remote_user $time_out $remote_port`
    ## func 2
    P_SSH_CMD --cmd $cmd --node $node(远端节点号)
    P_SSH_CMD --cmd $cmd --ip $remote_ip --password $remote_password --port $remote_port --user $remote_user --timeout $timeout
    # python
    conn = ssh_cmd.pssh_conn(remote_ip, remote_password,remote_port,remote_user,remote_timeout)
    exitcode, output = ssh_cmd.pssh_cmd(conn, cmd)
    
    # port:默认为22
    # user:默认为root
    # timeout: 默认不限制
    
    • 目录文件传输
    # bash
    ## func 1
    ### 本地文件传输到远端  
    `SSH_SCP $local_path/$file $REMOTE_USER@$REMOTE_IP:$remote_path "$REMOTE_PASSWD"`
    ### 远端文件传输到本地  
    `SSH_SCP $REMOTE_USER@$REMOTE_IP:$remote_path/$file $local_path "$REMOTE_PASSWD"`
    ## func 2
    ### 目录传输
    SFTP get/put --localdir $localdir --remotedir $remotedir
    ### 文件传输
    SFTP get/put --localdir $localdir --remotedir $remotedir --localfile/remotefile $localfile/$remotefile
    # python
    ### 目录传输
    import ssh_cmd, sftp
    conn = ssh_cmd.pssh_conn(remote_ip, remote_password,remote_port,remote_user,remote_timeout)
    psftp_get(conn,remote_dir, local_dir)
    psftp_put(local_dir=local_dir, remote_dir=remote_dir)
    ### 文件传输
    import ssh_cmd, sftp
    psftp_get(remote_dir, remote_file, local_dir)
    psftp_put(local_dir=local_dir, local_file=local_file, remote_dir=remote_dir)
    
    
    # get:从远端获取
    # put:传输到远端
    # localdir: 默认为当前目录
    # remotedir:默认为远端根目录
    
    • 获取空闲端口
    # bash
    GET_FREE_PORT $ip
    # python
    import free_port
    free_port.find_free_port(ip)
    
    • 检查端口是否被占用
    # bash 
    IS_FREE_PORT $port $ip
    # python
    import free_port
    free_port.is_free_port(port, ip)
    
    • 获取测试网卡
    # bash
    TEST_NIC $node_id
    # python
    import get_test_device
    get_test_nic(node_id)
    
    # node_id:默认为1号节点
    
    • 获取测试磁盘
    # bash
    TEST_DISK $node_id
    # python
    import get_test_device
    get_test_disk(node_id)
    
    # node_id:默认为1号节点
    
    • 睡眠等待
    # bash
    SLEEP_WAIT $wait_time $cmd
    # python
    import sleep_wait
    sleep_wait.sleep_wait(wait_time,cmd)
    
    • 远端重启等待
    # bash
    REMOTE_REBOOT_WAIT $node_id $wait_time
    

用例如何调试

  • 设置OET_PATH(mugen框架路径环境变量)之后,就可以在用例所在目录直接执行用例脚本

用例超时说明

  • 默认超时30m
  • 如果某条用例执行超过30m,在用例对TIMEOUT重新赋值

FAQ

  • 远程后台执行命令时,用例执行卡住,导致用例超时失败
    • 原因:ssh远程执行命令不会自动退出,会一直等待命令的控制台标准输出,直至命令运行信号结束
    • 解决方案:可以将标准输出与标准错误输出重定向到/dev/null,如此ssh就不会一直等待cmd > /dev/nul 2>&1 &

调用 QEMU 进行测试

在对 RISC-V 等非 x86-64 处理器架构上的软件包进行测试时,可以使用 qemu_test.py 脚本调用 QEMU 进行测试。

准备虚拟机

下载待测试的系统的镜像(.qcow2.zst 文件,需要使用 unzstd 命令解压为 .qcow2 文件)、引导加载程序(fw_payload_oe_uboot_*.bin)和启动脚本(start_vm.sh),保存到同一个目录中。

用启动脚本启动虚拟机,使用 Git 克隆 mugen 的 repo 到虚拟机下的一个目录(如 /root/mugen),再使用 dep_install.sh 脚本安装依赖。如果有需要,可以根据具体情况对虚拟机进行一些修改,比如进行需要网络的测试时需要安装 lshw 包。

将虚拟机准备完成后,使用 poweroff 命令关闭虚拟机,记下 .qcow2 镜像文件的名字。

准备物理机

在物理机(不一定要运行 openEuler)上使用 Git 克隆 mugen 的 repo。这里不需要使用 dep_install.sh 安装依赖。

qemu_test.py 依赖 paramiko 这个 Python 库,可以使用 pip 安装,也可以直接使用操作系统上的包管理器安装。如 Arch Linux 可以使用 pacman 安装 python-paramiko 包。

如果进行网络相关的测试,需要配置好网桥和 TAP 网卡。

首先,安装 bridge-utils 包,使用以下命令添加 br0 网桥:

# brctl addbr br0

再添加 TAP 网卡,需要安装 uml-utilities 包并开启 tun 内核模块。可以使用 tapsetup.sh 脚本批量添加:

$ sudo bash tapsetup.sh 10.198.101.1 50 br0 $(whoami)

其中,10.198.101.1 为网桥的 IP(脚本会自动为 IP 添加 /24),50 为 TAP 网卡个数,br0 为网桥的网卡名称,最后一个参数为允许使用该 TAP 网卡的用户名,这里使用 $(whoami) 获取当前用户名。

编写配置文件

qemu_test.py 脚本的配置文件使用 JSON 格式。以下是一份范例:

{
    "workingDir": ".",                      // 工作目录,即虚拟机文件保存的目录
    "bios": "fw_payload_oe_uboot_2304.bin", // 引导加载程序的文件名
    "drive": "mugen_ready.qcow2",           // 准备好的虚拟机镜像的文件名
    "user": "root",                         // 虚拟机的用户名
    "password": "openEuler12#$",            // 虚拟机的密码
    "threads": 4,                           // 测试线程数
    "cores": 4,                             // 为虚拟机分配的核心数
    "memory": 4,                            // 为虚拟机分配的内存容量,单位为 GB
    "mugenNative": 1,                       // 是否使用虚拟机上的测试套
    "detailed": 1,                          // 是否在屏幕上打印详细日志
    "addDisk": 1,                           // 添加的磁盘数量
    "mugenDir": "/root/mugen",              // 在虚拟机中 mugen 所在的目录
    "listFile": "lists/list_test",          // 需要测试的测试套列表文件
    "generate": 1,                          // 是否将测试套保存到物理机上
    "addNic": 1,                            // 是否添加网卡
    "multiMachine": 1,                      // 是否使用多台机器进行测试
    "tap num": 50,                          // 可以使用的 TAP 网卡数量
    "bridge ip": "10.198.101.114"           // 用于测试的网桥的 IP
}

需要注意的是,脚本无法处理 JSON 文件的行内注释。为了方便,这里提供一份不含注释的版本:

{
    "workingDir": ".", 
    "bios": "fw_payload_oe_uboot_2304.bin", 
    "drive": "mugen_ready.qcow2", 
    "user": "root", 
    "password": "openEuler12#$", 
    "threads": 4, 
    "cores": 4, 
    "memory": 4, 
    "mugenNative": 1, 
    "detailed": 1, 
    "addDisk": 1, 
    "mugenDir": "/root/mugen", 
    "listFile": "lists/list_test", 
    "generate": 1, 
    "addNic": 1, 
    "multiMachine": 1, 
    "tap num": 50, 
    "bridge ip": "10.198.101.114" 
}

进行测试

使用以下命令调用脚本,使用 config.json 作为配置文件进行测试:

$ python qemu_test.py -F config.json

在测试刚开始时,脚本会轮询判断虚拟机是否启动,可能会出现 SSH 连接相关的报错,这是正常的。

测试完成后,可以在工作目录下的以下文件夹找到与测试有关的信息:

  • suite2cases_out:被测试的测试套。

  • exec_log:测试套在运行时产生的日志。

  • logs:测试用例在运行时产生的日志。

也可以不使用配置文件,直接使用命令行参数提供配置,参见脚本 --help 参数的输出。

故障排查

在进行测试的过程中,如果在运行脚本较长时间之后,脚本没有输出测试日志和测试结果,而只是持续输出线程信息(如 Thread 0 is alive),这个时候可以尝试使用 SSH 连接到配置文件中配置的 SSH 端口(如上文中的 12055)。也可以使用 top 等工具判断 QEMU 是否正在运行。若均不正常,则说明脚本运行失败。

这个时候可以使用 Ctrl+C 关闭脚本,检查工作目录下的 logs 目录来判断有那些测试套已经测试完毕,再从列表文件中删除已经测试完毕的测试套,最后重新运行脚本开始测试。

mugen-riscv's People

Contributors

brsf11 avatar cuelive avatar duanxuemin avatar emilyliuliu avatar ethanzhang-55 avatar fuyahong2023 avatar geyaning avatar haiqiqin avatar huyahui8 avatar jevons0713 avatar kotorinminami avatar liujingjing25812 avatar mufiye avatar rlyuo avatar shilei522 avatar ssttkx avatar sunqingwei811 avatar suyun114 avatar ttz0601 avatar wangxiaorou92 avatar weilinfox avatar wenjunryou avatar wulei01 avatar xiangxinyong avatar xjun-z avatar yunxiangluo avatar zhanglu626 avatar zhangzhangpan avatar zjl-long avatar zuohanxu avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.