Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2caf64443 | |||
| 249e5ffc0a | |||
| bba3f5af67 | |||
| 9926d7781a | |||
| 464b03bbbd | |||
| dc3ae752a2 | |||
| c21128b8a6 | |||
| 44dcfde756 | |||
| d1026583f9 | |||
| 2e2b83387d | |||
| 64567f0f17 | |||
| 7433480309 | |||
| d72af21ac0 | |||
| 472685ee2e | |||
| 270ae3eec4 | |||
| 67d79fa231 | |||
| 72b4037183 | |||
| 44133fb9fc | |||
| c456fd112f | |||
| 57cebd9124 | |||
| b5dc2e8491 | |||
| 71ec8e0025 | |||
| cc0077006a | |||
| 69dd733af2 | |||
| 926b6876a6 | |||
| 18db9f5568 | |||
| 675d0a7207 | |||
| caf3b423af | |||
| cf340f1547 | |||
| 33b153652b | |||
| 72a1c28f79 | |||
| fbde8a1a14 | |||
| efe2f539c4 | |||
| 40347e7a88 | |||
| ad391aaee2 | |||
| 87a0feb5c2 | |||
| 786d391d8f | |||
| 5a3d8e1dc1 | |||
| 751cff3f31 | |||
| 5acfa31e6e |
98
.github/workflows/qemy-test.yml
vendored
Normal file
98
.github/workflows/qemy-test.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
name: Run test
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
TESTSUITE: ${{ vars.TESTSUITE }}
|
||||
QEMU_IMG: ${{ secrets.QEMU_IMG }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-qemu
|
||||
timeout-minutes: 4320
|
||||
steps:
|
||||
- name: install tools
|
||||
run: apt update && apt install -y wget iproute2 expect && pip3 install requests --break-system-packages
|
||||
- uses: https://gitee.com/ci-actions/checkout.git@v3
|
||||
- name: get the latest qemu image
|
||||
run: |
|
||||
BASE_URL="${QEMU_IMG%/*}"
|
||||
|
||||
VERSION=$(wget -qO- "$BASE_URL" \
|
||||
| grep -oP '[^"]+\.qcow2' \
|
||||
| grep -v 'sha256' \
|
||||
| sed -E 's/^[^-]+-//; s/\.qcow2$//' \
|
||||
| grep -E '^[0-9]' \
|
||||
| sort -u \
|
||||
| head -n1)
|
||||
|
||||
echo "The latest version: $VERSION"
|
||||
|
||||
pushd /test/images/openruyi
|
||||
FILE_NAME=$(basename $QEMU_IMG)
|
||||
echo "Download $FILE_NAME ..."
|
||||
rm -f openruyi-virt_riscv64.qcow2*
|
||||
wget -q --show-progress -O "/test/images/openruyi/openruyi-virt_riscv64.qcow2" "${QEMU_IMG}"
|
||||
export PATH="$PATH:/usr/local/qemu/bin"
|
||||
bash "$GITHUB_WORKSPACE/.github/workflows/scripts/qemu.sh" "${{ secrets.RISCV_DEFAULT_USERNAME }}" "${{ secrets.RISCV_DEFAULT_PASSWORD }}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Fail to start QEMU VM!"
|
||||
exit $?
|
||||
fi
|
||||
xz -9 -T 0 -k openruyi-virt_riscv64.qcow2
|
||||
popd
|
||||
- name: run tests
|
||||
timeout-minutes: 4320
|
||||
run: |
|
||||
set -x
|
||||
timeout 10 curl -s "${{ secrets.IMAGE_URL }}" || echo "no ${{ secrets.IMAGE_URL }}"
|
||||
SUB_DIR=qemu/${{ github.run_number}}-${DATA_STR}
|
||||
echo "SUB_DIR=$SUB_DIR" >> $GITHUB_ENV
|
||||
RESULT_DIR="/test/${SUB_DIR}"
|
||||
export RESULT_DIR="${RESULT_DIR}"
|
||||
mkdir -p "$RESULT_DIR"
|
||||
chmod +w "$RESULT_DIR"
|
||||
ls -la "$RESULT_DIR" || echo "no $RESULT_DIR"
|
||||
docker run --rm \
|
||||
-e OS_VERSION="${{ vars.OS_VERSION }}" \
|
||||
-e OS_ARCH="${{ vars.OS_ARCH }}" \
|
||||
-e CLOUDPODS_KEYSTONE_URL="${{ secrets.CLOUDPODS_KEYSTONE_URL }}" \
|
||||
-e CLOUDPODS_USER="${{ secrets.CLOUDPODS_USER }}" \
|
||||
-e CLOUDPODS_PASSWORD="${{ secrets.CLOUDPODS_PASSWORD }}" \
|
||||
-e GUEST_IMAGE_ID="${{ secrets.GUEST_IMAGE_ID }}" \
|
||||
-e DISK_IMAGE_ID="${{ secrets.DISK_IMAGE_ID }}" \
|
||||
-e CLOUDPODS_KVM_NET_LIST="${{ secrets.CLOUDPODS_KVM_NET_LIST }}" \
|
||||
-e SERVER_SKU="${{ secrets.SERVER_SKU }}" \
|
||||
-e SERVER_NAME_PREFIX="${{ github.event.repository.name }}-${{ github.run_number}}" \
|
||||
-e PASSWORD="${{ secrets.PASSWORD }}" \
|
||||
-e USER="${{ secrets.USER }}" \
|
||||
-e DELETE_DEFAULT_YUM_REPOS="yes" \
|
||||
-e ADD_YUM_REPOS="${{ secrets.ADD_YUM_REPOS }}" \
|
||||
-e OS_AUTOTEST_REPO_HTTPS="${{ vars.OS_AUTOTEST_REPO_HTTPS }}" \
|
||||
-e OS_AUTOTEST_BRANCH="${{ vars.OS_AUTOTEST_BRANCH }}" \
|
||||
-e CONCURRENCY="${{ vars.CONCURRENCY }}" \
|
||||
-e ONLY_TEST_EXIST_RPM="${{ vars.ONLY_TEST_EXIST_RPM }}" \
|
||||
-e EXIST_RPM_URLS="${{ secrets.EXIST_RPM_URLS }}" \
|
||||
-e TESTSUITE_MAX_TIMEOUT="${{ vars.TESTSUITE_MAX_TIMEOUT }}" \
|
||||
-e RISCV_BIOS="${{ vars.RISCV_BIOS }}" \
|
||||
${TESTSUITE:+-e TESTSUITE="$TESTSUITE"} \
|
||||
-e RISCV_DEFAULT_PASSWORD="${{ secrets.RISCV_DEFAULT_PASSWORD }}" \
|
||||
-e RISCV_DEFAULT_USERNAME="${{ secrets.RISCV_DEFAULT_USERNAME }}" \
|
||||
-e RISCV_IMAGE_URL="${{ secrets.IMAGE_URL }}/openruyi-virt_riscv64.qcow2.xz" \
|
||||
-e RISCV_VIRT_CODE_URL="${{ secrets.IMAGE_URL }}/RISCV_VIRT_CODE.fd" \
|
||||
-e RISCV_VIRT_VARS_URL="${{ secrets.IMAGE_URL }}/RISCV_VIRT_VARS.fd" \
|
||||
-v "$RESULT_DIR:/opt/os-autotest" \
|
||||
"${{ vars.OS_AUTOTEST_IMAGE }}" \
|
||||
bash -c 'python3 -m os-autotest-runner.run_autotest'
|
||||
ls -la "$RESULT_DIR" || echo "no $RESULT_DIR"
|
||||
ls -la /test || echo "no /test"
|
||||
ls -la $RESULT_DIR || echo "no $RESULT_DIR"
|
||||
- name: run test in github workflow
|
||||
run: |
|
||||
TITLE="qemu:os-autotest"
|
||||
if [ -n "$TESTSUITE" ]; then
|
||||
testsuites=$(awk -F, -v OFS=, 'NF>4{print $1,$2,$3,$4 "..."; next} 1' <<< "$TESTSUITE")
|
||||
TITLE="$TITLE:$testsuites"
|
||||
fi
|
||||
TITLE="$TITLE $RELEASE_VERSION ${DATA_STR:0:4}-${DATA_STR:4:2}-${DATA_STR:6:2} ${DATA_STR:8:2}-${DATA_STR:10:2}"
|
||||
python .github/workflows/scripts/stats.py --gitea-url "${{ github.api_url }}" --repo "${{ github.repository }}" --token "${{ secrets.RELEASE_TOKEN }}" --result "$RESULT_DIR" --log-url "${{ secrets.LOG_URL }}/$SUB_DIR" --title "$TITLE"
|
||||
43
.github/workflows/scripts/log-report.sh
vendored
Normal file
43
.github/workflows/scripts/log-report.sh
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 1. 定义根目录路径 (请根据实际情况修改)
|
||||
ROOT_DIR="${1:-$(pwd)/logs}"
|
||||
|
||||
# 2. 检查目录是否存在
|
||||
if [ ! -d "$ROOT_DIR" ]; then
|
||||
echo "错误: 目录 $ROOT_DIR 不存在"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "正在分析目录: $ROOT_DIR"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 3. 遍历根目录下的所有一级子目录
|
||||
# 使用 -mindepth 1 -maxdepth 1 确保只遍历第一层子目录
|
||||
# 使用 -type d 确保只处理目录
|
||||
for subdir in "$ROOT_DIR"/*/; do
|
||||
# 如果没有子目录,循环可能会直接跳过,这里做一个安全检查
|
||||
[ -d "$subdir" ] || continue
|
||||
|
||||
# 4. 查找该子目录下最大的 .log 文件
|
||||
# ls -1 列出文件
|
||||
# sort 按名称排序 (因为你要的是"按名称排序最大",即字母顺序最后)
|
||||
# tail -n 1 取最后一行,即最大的那个
|
||||
max_log_file=$(ls -1 "$subdir"*.log 2>/dev/null | sort | tail -n 1)
|
||||
|
||||
# 5. 检查是否找到了 log 文件
|
||||
if [ -n "$max_log_file" ] && [ -f "$max_log_file" ]; then
|
||||
echo ">>> 正在分析文件: $max_log_file"
|
||||
|
||||
# 6. 使用 grep 获取 warn 和 error 信息及其前后 5 行
|
||||
# -i : 忽略大小写 (匹配 Warn, WARN, warn)
|
||||
# -E : 使用扩展正则表达式 (匹配 warn 或 error)
|
||||
# -C 5 : 显示匹配行的前后 5 行 (Context)
|
||||
# --color=auto : 高亮显示关键词 (可选,方便查看)
|
||||
grep -n -E -C 5 --color=auto "Failed |Error:" "$max_log_file" | sed 's/^--$/----------------------------------------/'
|
||||
|
||||
echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
|
||||
else
|
||||
echo ">>> 在 $subdir 中未找到 .log 文件"
|
||||
fi
|
||||
done
|
||||
87
.github/workflows/scripts/qemu.sh
vendored
Normal file
87
.github/workflows/scripts/qemu.sh
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
USER="$1"
|
||||
PASS="$2"
|
||||
|
||||
START_PORT=12060
|
||||
PORT=$START_PORT
|
||||
while ss -tln | grep -qE ":${PORT}\b"; do
|
||||
((PORT++))
|
||||
done
|
||||
|
||||
QEMU_CMD="qemu-system-riscv64"
|
||||
VM_ARGS="-nographic -machine virt,pflash0=pflash0,pflash1=pflash1 \
|
||||
-smp 8 -m 12G \
|
||||
-cpu rva23s64 \
|
||||
-blockdev node-name=pflash0,driver=file,read-only=on,filename=RISCV_VIRT_CODE.fd \
|
||||
-blockdev node-name=pflash1,driver=file,filename=RISCV_VIRT_VARS.fd \
|
||||
-drive file=openRuyi-2026.03-Server-cloud.qcow2,format=qcow2,id=hd0,if=none \
|
||||
-object rng-random,filename=/dev/urandom,id=rng0 \
|
||||
-device virtio-vga \
|
||||
-device virtio-rng-device,rng=rng0 \
|
||||
-device virtio-blk-device,drive=hd0 \
|
||||
-device virtio-net-device,netdev=usernet \
|
||||
-netdev user,id=usernet,hostfwd=tcp::${PORT}-:22 \
|
||||
-device qemu-xhci -usb -device usb-kbd -device usb-tablet"
|
||||
|
||||
expect <<-EOF
|
||||
set timeout 600
|
||||
puts "正在启动虚拟机..."
|
||||
spawn $QEMU_CMD $VM_ARGS
|
||||
|
||||
expect {
|
||||
"Press Control-D to continue" {
|
||||
puts "\n检测到 Emergency Mode,发送 Ctrl+D..."
|
||||
send "\004"
|
||||
exp_continue
|
||||
}
|
||||
|
||||
-re "login:|Username:" {
|
||||
puts "\n发现登录界面,输入用户名..."
|
||||
send "${USER}\r"
|
||||
exp_continue
|
||||
}
|
||||
|
||||
-re "\[Pp\]assword:" {
|
||||
puts "\n输入密码..."
|
||||
send "${PASS}\r"
|
||||
exp_continue
|
||||
}
|
||||
|
||||
"Login incorrect" {
|
||||
puts "\n登录失败:用户名或密码错误"
|
||||
exit 2
|
||||
}
|
||||
|
||||
-re {[#$]|root@.*#} {
|
||||
puts "\n登录成功!"
|
||||
exit 0
|
||||
}
|
||||
|
||||
-re {\x1b\[[0-9;]*[RfH]} {
|
||||
exp_continue
|
||||
}
|
||||
|
||||
timeout {
|
||||
puts "\n虚拟机启动或登录超时"
|
||||
exit 1
|
||||
}
|
||||
|
||||
eof {
|
||||
puts "\nQEMU 进程意外关闭"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
RET=$?
|
||||
|
||||
if [ $RET -eq 0 ]; then
|
||||
echo "虚拟机启动成功"
|
||||
elif [ $RET -eq 2 ]; then
|
||||
echo "用户名或密码错误,登录失败"
|
||||
else
|
||||
echo "启动失败,退出码 $RET"
|
||||
fi
|
||||
|
||||
exit $RET
|
||||
128
.github/workflows/scripts/runtest.sh
vendored
Normal file
128
.github/workflows/scripts/runtest.sh
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/bash
|
||||
set -x
|
||||
|
||||
RUNDIR="$(pwd)"
|
||||
TESTSUITE_FILE="${RUNDIR}/.os-autotest/testsuite"
|
||||
PKGTEST_FILE="${RUNDIR}/.os-autotest/pkg-install"
|
||||
SUITE_DIR="${RUNDIR}/suite2cases"
|
||||
|
||||
LOG_INFO() {
|
||||
printf "$(date +'%Y-%m-%d %T') $0 [ INFO ] %s\n" "$@"
|
||||
}
|
||||
|
||||
LOG_WARN() {
|
||||
printf "$(date +'%Y-%m-%d %T') $0 [ WARN ] %s\n" "$@"
|
||||
}
|
||||
|
||||
LOG_ERROR() {
|
||||
printf "$(date +'%Y-%m-%d %T') $0 [ ERROR ] %s\n" "$@"
|
||||
}
|
||||
|
||||
if [ -z "${RESULT_DIR}" ]; then
|
||||
LOG_ERROR "Please export RESULT_DIR!"
|
||||
exit 1
|
||||
else
|
||||
rm -rf "${RESULT_DIR}/*"
|
||||
fi
|
||||
|
||||
LOGFILE="${RESULT_DIR}/os-autotest.log"
|
||||
|
||||
dnf install -y lshw rsync jq --refresh
|
||||
|
||||
mkdir -p "${RESULT_DIR}/source/suite2cases"
|
||||
|
||||
if [ ! -s "${TESTSUITE_FILE}" ] && [ ! -s "${PKGTEST_FILE}" ]; then
|
||||
LOG_WARN "No info from ${TESTSUITE_FILE}/${PKGTEST_FILE}, no need to run testsuite."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pushd "$RUNDIR"
|
||||
bash dep_install.sh
|
||||
dnf install -y hostname --refresh
|
||||
[ -f /usr/bin/yum ] || ln -sf /usr/bin/dnf /usr/bin/yum
|
||||
rm -rf conf results logs
|
||||
bash mugen.sh -c --ip $(hostname -I | awk '{print $1}') --password openruyi --user openruyi --port 22
|
||||
|
||||
if [ -s "$TESTSUITE_FILE" ]; then
|
||||
mapfile -t patterns < <(sort -u "$TESTSUITE_FILE" | sed '/^\s*$/d')
|
||||
|
||||
LOG_INFO "start match $TESTSUITE_FILE ..."
|
||||
|
||||
pushd "$SUITE_DIR" || { LOG_INFO "no $SUITE_DIR found and exit."; exit 0; }
|
||||
|
||||
for item in "${patterns[@]}"; do
|
||||
LOG_INFO ">>> $item:"
|
||||
found=false
|
||||
|
||||
if [[ "$item" == *\* ]]; then
|
||||
item="${item%\*}"
|
||||
matches=$(find . -type f -name "${item}*.json")
|
||||
else
|
||||
matches=$(find . -type f -name "${item}.json")
|
||||
fi
|
||||
|
||||
if [ -n "$matches" ]; then
|
||||
for file in $matches; do
|
||||
if [ -f "$file" ]; then
|
||||
full_name=$(basename "$file")
|
||||
suite_name="${full_name%.json}"
|
||||
suite2cases_path=$(jq -r '.path' "$file")
|
||||
LOG_INFO "[FOUND] run suitecases $suite_name"
|
||||
found=true
|
||||
pushd "$RUNDIR" || continue
|
||||
LOG_INFO "start to run bash mugen.sh -f $suite_name -x"
|
||||
if [ "$suite_name" == "smoke_pkg_install" ]; then
|
||||
if [ -s "$PKGTEST_FILE" ]; then
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] || continue
|
||||
export PKG_INSTALL=$line
|
||||
ORIGIN_LOGS=logs/${suite_name}/test_pkg_install_uninstall
|
||||
TARGET_LOGS=logs/${suite_name}/test_${PKG_INSTALL}_install_uninstall
|
||||
[ -d $ORIGIN_LOGS ] && rm -rf $ORIGIN_LOGS
|
||||
[ -d $TARGET_LOGS ] && rm -rf $TARGET_LOGS
|
||||
for status in succeed fail; do
|
||||
rst_file="results/${suite_name}/${status}/test_pkg_install_uninstall"
|
||||
[ -f "$rst_file" ] && rm -f "$rst_file"
|
||||
done
|
||||
LOG_INFO " package: ${PKG_INSTALL}" | tee -a "${LOGFILE}"
|
||||
bash mugen.sh -f "$suite_name" -x 2>&1 | tee -a "${LOGFILE}"
|
||||
[ -d $ORIGIN_LOGS ] && mv $ORIGIN_LOGS $TARGET_LOGS
|
||||
for status in succeed fail; do
|
||||
target="results/${suite_name}/${status}/test_pkg_install_uninstall"
|
||||
[ -f "$target" ] && mv "$target" "results/${suite_name}/${status}/test_${PKG_INSTALL}_install_uninstall"
|
||||
done
|
||||
done < "$PKGTEST_FILE"
|
||||
else
|
||||
LOG_INFO " No info in .os-autotest/pkg-install!"
|
||||
continue
|
||||
fi
|
||||
else
|
||||
bash mugen.sh -f "$suite_name" -x 2>&1 | tee -a "${LOGFILE}"
|
||||
fi
|
||||
LOG_INFO "end to run bash mugen.sh -f $suite_name -x"
|
||||
suite2cases_path=$(echo "$suite2cases_path" | sed 's|.*testcases/|testcases/|')
|
||||
rsync -RravL "$suite2cases_path" "$RESULT_DIR/source/"
|
||||
echo "$suite_name" >> "$RESULT_DIR/testsuits"
|
||||
popd
|
||||
cp "$file" "$RESULT_DIR/source/suite2cases"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$found" = false ]; then
|
||||
LOG_WARN "[UNFOUND] no suitecases for $item"
|
||||
fi
|
||||
done
|
||||
|
||||
popd
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
LOG_INFO "start to copy results ..."
|
||||
mkdir -p "$RESULT_DIR/results" "$RESULT_DIR/logs"
|
||||
cp -r "$RUNDIR"/results/* "$RESULT_DIR/results/"
|
||||
cp -r "$RUNDIR"/logs/* "$RESULT_DIR/logs/"
|
||||
LOG_INFO "end to copy results."
|
||||
|
||||
exit 0
|
||||
94
.github/workflows/scripts/stats.py
vendored
Normal file
94
.github/workflows/scripts/stats.py
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/python3
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
_SUMMARY_FILE = "summary_results.json"
|
||||
|
||||
def parse_json_files(result_path, filename=_SUMMARY_FILE):
|
||||
if result_path.startswith("http") or result_path.startswith("ftp"):
|
||||
try:
|
||||
response = requests.get(result_path + "/" + _SUMMARY_FILE, timeout=10)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
return data
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"request for {result_path}/{_SUMMARY_FILE} failed: ", e)
|
||||
raise
|
||||
except ValueError as e: # 包括 JSONDecodeError
|
||||
print("get json info failed:", e)
|
||||
raise
|
||||
else:
|
||||
file_path = os.path.join(result_path, filename)
|
||||
if os.path.isfile(file_path):
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
print(f"read {file_path} successfully")
|
||||
return data
|
||||
except (json.JSONDecodeError, OSError) as e:
|
||||
print(f"read {file_path} failed: {e}")
|
||||
raise
|
||||
else:
|
||||
print(f"{file_path} does not exist")
|
||||
raise FileNotFoundError(f"{file_path} does not exist")
|
||||
|
||||
def generate_markdown_table(headers, rows, log_url):
|
||||
if not rows:
|
||||
return ""
|
||||
|
||||
header_line = "| " + " | ".join(headers) + " |"
|
||||
separator_line = "| " + " | ".join(["---"] * len(headers)) + " |"
|
||||
body_lines = ["| " + " | ".join(row[:-1]) + " | [" + ("\u2705" if row[-1] == "passed" else "\u274C") + row[-1] + "](" + "/".join([log_url, "logs", row[0], row[1]]) + ")" for row in rows]
|
||||
|
||||
return "\n".join([header_line, separator_line] + body_lines)
|
||||
|
||||
|
||||
def create_gitea_issue(gitea_url, token, repo, title, body):
|
||||
"""create issue"""
|
||||
api_url = f"{gitea_url.rstrip('/')}/repos/{repo}/issues"
|
||||
|
||||
headers = {
|
||||
"Authorization": f"token {token}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"title": title,
|
||||
"body": body
|
||||
}
|
||||
|
||||
response = requests.post(api_url, headers=headers, json=payload)
|
||||
if response.status_code == 201:
|
||||
issue = response.json()
|
||||
print(f"create issue successfully: #{issue['number']} - {issue['html_url']}")
|
||||
return 0, issue["number"]
|
||||
else:
|
||||
print(f"fail to create issuse (HTTP {response.status_code}): {response.text}")
|
||||
# response.raise_for_status()
|
||||
raise RuntimeError(f"Unexpected status code: {response.status_code}", response=response)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="测试结果")
|
||||
parser.add_argument("--result", required=True, help="测试结果存放目录路径")
|
||||
parser.add_argument("--gitea-url", required=True, help="Gitea 实例 URL,例如 https://gitea.example.com")
|
||||
parser.add_argument("--repo", required=True, help="完整的仓库名")
|
||||
parser.add_argument("--token", required=True, help="Gitea Personal Access Token")
|
||||
parser.add_argument("--title", default=f"openRuyi 测试报告 {datetime.now()}", help="Issue 标题")
|
||||
parser.add_argument("--log-url", required=True, default="测试报告存放地址", help="Issue 标题")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
data = parse_json_files(args.result)
|
||||
if "data" not in data.keys() or data["data"] is None or len(data["data"]) == 0:
|
||||
print(f"no test result, exit 0")
|
||||
return
|
||||
markdown_stats = generate_markdown_table(data["head"], data["data"], args.log_url)
|
||||
issue_number = create_gitea_issue(args.gitea_url, args.token, args.repo, args.title, markdown_stats)
|
||||
print(f"created issue number: {issue_number}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
137
.github/workflows/scripts/summary.py
vendored
Normal file
137
.github/workflows/scripts/summary.py
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import json
|
||||
import csv
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import argparse
|
||||
|
||||
SOURCE_DIR = "./"
|
||||
RESULT_DIR = "./"
|
||||
# os.environ['LOG_DIR'] = os.path.join(os.getcwd(), "log")
|
||||
os.environ['LOG_DIR'] = "./log"
|
||||
os.environ['LOG_NAME'] = "os-autotest"
|
||||
|
||||
from log import log
|
||||
|
||||
def get_testsuite_info(testsuite):
|
||||
json_file = os.path.join(SOURCE_DIR, "suite2cases", testsuite + ".json")
|
||||
if os.path.exists(json_file):
|
||||
with open(json_file, 'r', encoding='utf-8') as f:
|
||||
suite_data = json.load(f)
|
||||
return suite_data
|
||||
else:
|
||||
log.warning(f"{testsuite} not exists")
|
||||
return None
|
||||
|
||||
def get_os_autotest_testsuite_result_data(testsuite):
|
||||
log.info(f"begin to get testsuite {testsuite} result data...")
|
||||
data=[]
|
||||
all_cases = []
|
||||
succeed_path = f"{RESULT_DIR}/results/{testsuite}/succeed"
|
||||
failed_path = f"{RESULT_DIR}/results/{testsuite}/failed"
|
||||
skipped_path = f"{RESULT_DIR}/results/{testsuite}/skipped"
|
||||
if os.path.exists(succeed_path):
|
||||
for file_name in os.listdir(succeed_path):
|
||||
if file_name in all_cases:
|
||||
continue
|
||||
temp = [testsuite, file_name, "passed"]
|
||||
data.append(temp)
|
||||
all_cases.append(file_name)
|
||||
else:
|
||||
log.warning(f"{succeed_path} not exists")
|
||||
if os.path.exists(failed_path):
|
||||
for file_name in os.listdir(failed_path):
|
||||
if file_name in all_cases:
|
||||
continue
|
||||
temp = [testsuite, file_name, "failed"]
|
||||
data.append(temp)
|
||||
all_cases.append(file_name)
|
||||
else:
|
||||
log.warning(f"{failed_path} not exists")
|
||||
if os.path.exists(skipped_path):
|
||||
for file_name in os.listdir(skipped_path):
|
||||
if file_name in all_cases:
|
||||
continue
|
||||
temp = [testsuite, file_name, "skipped"]
|
||||
data.append(temp)
|
||||
all_cases.append(file_name)
|
||||
else:
|
||||
log.warning(f"{skipped_path} not exists")
|
||||
suite_data=get_testsuite_info(testsuite)
|
||||
if not suite_data:
|
||||
log.warning(f"{testsuite} not found in mugen sources.")
|
||||
return None
|
||||
script_path_origin=suite_data["path"]
|
||||
script_dir=SOURCE_DIR+ "/" +"/".join(script_path_origin.split("/")[1:])
|
||||
for elem in suite_data["cases"]:
|
||||
case_name=elem["name"]
|
||||
result = subprocess.run(['find', script_dir, '-name', f"{case_name}.sh"], capture_output=True, text=True,
|
||||
check=True)
|
||||
found_files = result.stdout.splitlines()
|
||||
if not found_files:
|
||||
log.warning(f"{case_name}.sh not found in {script_dir}")
|
||||
continue
|
||||
if case_name not in all_cases:
|
||||
if testsuite == "smoke_pkg_install" and case_name == "test_pkg_install_uninstall":
|
||||
continue
|
||||
temp = [testsuite, case_name, "not run or exception in running, please run manual"]
|
||||
data.append(temp)
|
||||
return data
|
||||
|
||||
def get_os_autotest_summary_results(testsuite_list):
|
||||
summary_results_json_path = f"{RESULT_DIR}/summary_results.json"
|
||||
summary_results_csv_path = f"{RESULT_DIR}/summary_results.csv"
|
||||
header = ["testsuite", "testcase", "result"]
|
||||
datas={
|
||||
"head": header,
|
||||
"data": []
|
||||
}
|
||||
for testsuite in testsuite_list:
|
||||
data = get_os_autotest_testsuite_result_data(testsuite)
|
||||
if data is not None:
|
||||
datas["data"].extend(data)
|
||||
with open(summary_results_json_path, "w+", encoding="utf-8") as f:
|
||||
json.dump(datas, f, ensure_ascii=False, indent=4)
|
||||
with open(summary_results_csv_path, "w+", encoding="utf-8") as f:
|
||||
csv_writer = csv.writer(f)
|
||||
csv_writer.writerow(header)
|
||||
csv_writer.writerows(datas["data"])
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="整理测试结果")
|
||||
parser.add_argument("--testsuits", required=True, help="测试套名称文件路径")
|
||||
parser.add_argument("--result", required=True, help="测试结果存放目录路径")
|
||||
parser.add_argument("--source", required=True, help="测试用例源码路径")
|
||||
|
||||
args = parser.parse_args()
|
||||
testsuits_file = args.testsuits
|
||||
global SOURCE_DIR
|
||||
SOURCE_DIR = args.source
|
||||
global RESULT_DIR
|
||||
RESULT_DIR = args.result
|
||||
|
||||
with open(testsuits_file, 'r', encoding='utf-8') as f:
|
||||
testsuit_names = f.read().splitlines()
|
||||
|
||||
print(testsuit_names)
|
||||
get_os_autotest_summary_results(testsuit_names)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
# python summary.py --testsuits "./mugen/testsuits" --result "./mugen" --source "/home/xlab/workspaces/ruyi/mugen"
|
||||
# path = "./mugen/testsuits"
|
||||
# json_files = [f for f in os.listdir(path) if f.endswith('.json')]
|
||||
# print(json_files)
|
||||
|
||||
# from pathlib import Path
|
||||
# path = Path("./mugen/testsuits")
|
||||
# testsuit_names = [f.stem for f in path.glob("*.json")]
|
||||
# print(testsuit_names)
|
||||
# with open('./mugen/testsuits', 'r', encoding='utf-8') as f:
|
||||
# testsuit_names = f.read().splitlines()
|
||||
|
||||
# print(testsuit_names)
|
||||
# get_os_autotest_summary_results(testsuit_names)
|
||||
45
.github/workflows/smoke-test.yml
vendored
Normal file
45
.github/workflows/smoke-test.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: Run smoke test on SG2044
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
TESTSUITE: ${{ vars.TESTSUITE }}
|
||||
PKGTEST: ${{ vars.PKGTEST }}
|
||||
LOGDIR: ${{ secrets.LOGDIR }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: openruyi-175
|
||||
timeout-minutes: 4320
|
||||
steps:
|
||||
- name: install tools
|
||||
run: sudo dnf install -y git nodejs rsync sshpass --refresh && pip3 install requests python3-log --break-system-packages
|
||||
- uses: https://gitee.com/ci-actions/checkout.git@v3
|
||||
- name: run tests
|
||||
run: |
|
||||
set -x
|
||||
DATA_STR="$(date +%Y%m%d%H%M%S)"
|
||||
SUB_DIR=${{ github.run_number}}-${DATA_STR}
|
||||
RESULT_DIR="${LOGDIR}/${SUB_DIR}"
|
||||
export RESULT_DIR="${RESULT_DIR}"
|
||||
mkdir -p .os-autotest ${RESULT_DIR}
|
||||
echo "$TESTSUITE" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed '/^\s*$/d' > .os-autotest/testsuite
|
||||
echo "$PKGTEST" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed '/^\s*$/d' > .os-autotest/pkg-install
|
||||
bash .github/workflows/scripts/runtest.sh
|
||||
|
||||
if [ -n "$(find "${RESULT_DIR}/source/suite2cases" -maxdepth 0 -empty)" ]; then
|
||||
LOG_WARN "<<< no suite2cases found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bash .github/workflows/scripts/log-report.sh "${RESULT_DIR}/logs"
|
||||
|
||||
python .github/workflows/scripts/summary.py --testsuits ".os-autotest/testsuite" --result "${RESULT_DIR}" --source "${RESULT_DIR}/source"
|
||||
sshpass -p "${{ secrets.IMAGE_BACKUP_HOST_PWD }}" rsync -av -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" "${RESULT_DIR}" "${{ secrets.IMAGE_BACKUP_HOST_USER }}@${{ secrets.IMAGE_BACKUP_HOST }}:${{ secrets.LOGDIR }}/sg2044/"
|
||||
TITLE="sg2044:os-autotest"
|
||||
if [ -n "$TESTSUITE" ]; then
|
||||
testsuites=$(awk -F, -v OFS=, 'NF>4{print $1,$2,$3,$4 "..."; next} 1' <<< "$TESTSUITE")
|
||||
TITLE="$TITLE:$testsuites"
|
||||
fi
|
||||
TITLE="$TITLE $RELEASE_VERSION ${DATA_STR:0:4}-${DATA_STR:4:2}-${DATA_STR:6:2} ${DATA_STR:8:2}-${DATA_STR:10:2}"
|
||||
python .github/workflows/scripts/stats.py --gitea-url "${{ github.api_url }}" --repo "${{ github.repository }}" --token "${{ secrets.RELEASE_TOKEN }}" --result "${RESULT_DIR}" --log-url "${{ secrets.LOG_URL }}/sg2044/${SUB_DIR}" --title "$TITLE"
|
||||
@@ -38,14 +38,6 @@ def get_test_nic(node=1):
|
||||
Returns:
|
||||
[str]: 网卡名
|
||||
"""
|
||||
exitcode, tmpfile = rpm_manage.rpm_install(pkgs="lshw", node=node)
|
||||
if exitcode != 0:
|
||||
mugen_log.logging(
|
||||
"error",
|
||||
"Failed to install the dependent software package required to obtain the network card.",
|
||||
)
|
||||
sys.exit(exitcode)
|
||||
|
||||
if os.environ.get("NODE" + str(node) + "_LOCALTION") == "local":
|
||||
dev_info = subprocess.getoutput("cat /proc/device-tree/model")
|
||||
if "Lichee Pi 4A" in dev_info:
|
||||
@@ -90,9 +82,6 @@ def get_test_nic(node=1):
|
||||
|
||||
ssh_cmd.pssh_close(conn)
|
||||
|
||||
if tmpfile is not None:
|
||||
rpm_manage.rpm_remove(node=node, tmpfile=tmpfile)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
@@ -107,12 +96,12 @@ def get_test_disk(node=1):
|
||||
"""
|
||||
if os.environ.get("NODE" + str(node) + "_LOCALTION") == "local":
|
||||
used_disk = subprocess.getoutput(
|
||||
"lsblk -l | grep -e '/.*\|\[.*\]' | awk '{print $1}' | tr -d '[0-9]' | uniq | sed -e ':a;N;$!ba;s/\\n/ /g'"
|
||||
r"lsblk -l | grep -e '/.*\|\[.*\]' | awk '{print $1}' | tr -d '[0-9]' | uniq | sed -e ':a;N;$!ba;s/\\n/ /g'"
|
||||
)
|
||||
|
||||
test_disk = subprocess.getoutput(
|
||||
"lsblk -n | grep 'disk' | grep -v '└─.*\|"
|
||||
+ used_disk.replace(" ", "\|")
|
||||
r"lsblk -n | grep 'disk' | grep -v '└─.*\|"
|
||||
+ used_disk.replace(" ", r"\|")
|
||||
+ "' | awk '{print $1}' | sed -e ':a;N;$!ba;s/\\n/ /g'"
|
||||
)
|
||||
else:
|
||||
@@ -124,12 +113,12 @@ def get_test_disk(node=1):
|
||||
)
|
||||
used_disk = ssh_cmd.pssh_cmd(
|
||||
conn,
|
||||
"lsblk -l | grep -e '/.*\|\[.*\]' | awk '{print $1}' | tr -d '[0-9]' | uniq | sed -e ':a;N;$!ba;s/\\n/ /g'",
|
||||
r"lsblk -l | grep -e '/.*\|\[.*\]' | awk '{print $1}' | tr -d '[0-9]' | uniq | sed -e ':a;N;$!ba;s/\\n/ /g'",
|
||||
)[1]
|
||||
test_disk = ssh_cmd.pssh_cmd(
|
||||
conn,
|
||||
"lsblk -n | grep 'disk' | grep -v '└─.*\|"
|
||||
+ used_disk.replace(" ", "\|")
|
||||
r"lsblk -n | grep 'disk' | grep -v '└─.*\|"
|
||||
+ used_disk.replace(" ", r"\|")
|
||||
+ "' | awk '{print $1}' | sed -e ':a;N;$!ba;s/\\n/ /g'",
|
||||
)[1]
|
||||
|
||||
|
||||
@@ -95,25 +95,25 @@ def rpm_install(pkgs, node=1, tmpfile=""):
|
||||
conn=conn,
|
||||
cmd="dnf --assumeno install "
|
||||
+ pkgs
|
||||
+ ' 2>&1 | grep -wE "$(echo '
|
||||
+ " 2>&1 | grep -wE \"$(echo '"
|
||||
+ repoList
|
||||
+ " | sed 's/ /|/g')\" | grep -wE \"$(uname -m)|noarch\"| awk '{print $1}'",
|
||||
+ "' | sed 's/ /|/g')\" | grep -wE \"$(uname -m)|noarch\"| awk '{print $1}'",
|
||||
)
|
||||
else:
|
||||
depCode, depList = func(
|
||||
conn=conn,
|
||||
cmd="dnf --assumeno install "
|
||||
+ pkgs
|
||||
+ ' 2>&1 | grep -wE "$(echo '
|
||||
+ " 2>&1 | grep -wE \"$(echo '"
|
||||
+ repoList
|
||||
+ " | sed 's/ /|/g')\" | grep -wE \"$(uname -m)|noarch\"| grep -vE \"$(echo "
|
||||
+ "' | sed 's/ /|/g')\" | grep -wE \"$(uname -m)|noarch\"| grep -vE \"$(echo "
|
||||
+ upList
|
||||
+ " | sed 's/ /|/g')\" | awk '{print $1}'",
|
||||
)
|
||||
if depCode != 0:
|
||||
return depCode, depList
|
||||
|
||||
exitcode, result = func(conn=conn, cmd="dnf -y install " + pkgs)
|
||||
exitcode, result = func(conn=conn, cmd="dnf --refresh -y install " + pkgs)
|
||||
|
||||
if tmpfile == "":
|
||||
tmpfile = tempfile.mkstemp(dir="/tmp")[1]
|
||||
|
||||
@@ -23,6 +23,7 @@ import json
|
||||
import re
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from collections import OrderedDict
|
||||
|
||||
SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(SCRIPT_PATH)
|
||||
@@ -67,7 +68,7 @@ def suite_path(suite):
|
||||
|
||||
try:
|
||||
with open(suite_json, "r") as f:
|
||||
suite_data = json.loads(f.read())
|
||||
suite_data = json.loads(f.read(), object_pairs_hook=OrderedDict)
|
||||
if suite_data["path"] is None:
|
||||
mugen_log.logging("error", "json文件:%s中没有path值." % suite_json)
|
||||
sys.exit(1)
|
||||
@@ -109,7 +110,7 @@ def suite_cases(suite):
|
||||
|
||||
try:
|
||||
with open(suite_json, "r") as f:
|
||||
suite_data = json.loads(f.read())
|
||||
suite_data = json.loads(f.read(), object_pairs_hook=OrderedDict)
|
||||
if suite_data["cases"] is None:
|
||||
mugen_log.logging("error", "json文件:%s中没有cases值." % suite_json)
|
||||
sys.exit(1)
|
||||
|
||||
2
mugen.sh
2
mugen.sh
@@ -106,7 +106,7 @@ function modify_conf() {
|
||||
}
|
||||
|
||||
function load_conf() {
|
||||
rm -rf "${OET_PATH}"/results
|
||||
# rm -rf "${OET_PATH}"/results
|
||||
|
||||
export_var=$(python3 "${OET_PATH}"/libs/locallibs/read_conf.py env-var)
|
||||
test $? -ne 0 && exit 1
|
||||
|
||||
12
suite2cases/performance_test/openruyi_unixbench.json
Normal file
12
suite2cases/performance_test/openruyi_unixbench.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"path": "$OET_PATH/testcases/performance_test/openruyi_unixbench",
|
||||
"machine num": 1,
|
||||
"cases": [
|
||||
{
|
||||
"name": "test_perf_unixbench",
|
||||
"desc": "执行 unixbench 跑分测试",
|
||||
"machine num": 1,
|
||||
"timeout": 3600
|
||||
}
|
||||
]
|
||||
}
|
||||
33
suite2cases/smoke_test/openruyi/smoke_openruyi.json
Normal file
33
suite2cases/smoke_test/openruyi/smoke_openruyi.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"path": "$OET_PATH/testcases/smoke_test/smoke_openruyi",
|
||||
"machine num": 1,
|
||||
"cases": [
|
||||
{
|
||||
"name": "or_test_timedatectl",
|
||||
"machine num": 1,
|
||||
"add network interface": 0,
|
||||
"add disk": []
|
||||
},
|
||||
{
|
||||
"name": "oe_test_home_directory",
|
||||
"machine num": 1,
|
||||
"add network interface": 0,
|
||||
"add disk": []
|
||||
},
|
||||
{
|
||||
"name": "or_test_ssh_disable_root",
|
||||
"machine num": 1,
|
||||
"desc": "ssh 默认关闭 root 用户登录"
|
||||
},
|
||||
{
|
||||
"name": "or_test_gcc_build",
|
||||
"machine num": 1,
|
||||
"desc": "gcc 编译链测试"
|
||||
},
|
||||
{
|
||||
"name": "or_test_llvm_build",
|
||||
"machine num": 1,
|
||||
"desc": "LLVM 编译链测试"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
suite2cases/smoke_test/openruyi/smoke_pkg_install.json
Normal file
10
suite2cases/smoke_test/openruyi/smoke_pkg_install.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"path": "$OET_PATH/testcases/smoke_test/smoke_pkg_install",
|
||||
"machine num": 1,
|
||||
"cases": [
|
||||
{
|
||||
"name": "test_pkg_install_uninstall",
|
||||
"desc": "测试软件包的安装功能"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Copyright (c) 2024 ISCAS .ALL rights reserved.
|
||||
# This program is licensed under Mulan PSL v2.
|
||||
# You can use it according to the terms and conditions of the Mulan PSL v2.
|
||||
# http://license.coscl.org.cn/MulanPSL2
|
||||
# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
# #############################################
|
||||
# @Author : honghua
|
||||
# @Contact : honghua@iscas.ac.cn
|
||||
# @Date : 2026-01-07
|
||||
# @License : Mulan PSL v2
|
||||
# @Desc : 执行 unixbench 跑分工具,评估。
|
||||
# ############################################
|
||||
|
||||
source "$OET_PATH/libs/locallibs/common_lib.sh"
|
||||
|
||||
function pre_test() {
|
||||
LOG_INFO "Start to prepare the test environment."
|
||||
DNF_INSTALL "unixbench"
|
||||
LOG_INFO "End to prepare the test environment."
|
||||
}
|
||||
|
||||
function get_system_info() {
|
||||
os_name=$(grep "^PRETTY_NAME=" /etc/os-release | cut -d'"' -f2 | awk '{print $1}')
|
||||
os_version=$(grep "^VERSION=" /etc/os-release | cut -d'"' -f2)
|
||||
os_arch=$(uname -m)
|
||||
cpu=$(nproc)
|
||||
memory=$(free -g | awk '/^Mem:/{print $2}')
|
||||
}
|
||||
|
||||
function escape_json_string() {
|
||||
local str="$1"
|
||||
str="${str//\\/\\\\}"
|
||||
str="${str//\"/\\\"}"
|
||||
str="${str//$'\n'/\\n}"
|
||||
str="${str//$'\r'/\\r}"
|
||||
str="${str//$'\t'/\\t}"
|
||||
printf '%s' "$str"
|
||||
}
|
||||
|
||||
function parse_unixbench_result() {
|
||||
local log_content="$1"
|
||||
|
||||
score=$(echo "$log_content" | grep "System Benchmarks Index Score" | awk '{print $NF}')
|
||||
|
||||
[ -z "$score" ] && score="unknown"
|
||||
}
|
||||
|
||||
function send_result() {
|
||||
local api_url="https://data-baicao-verify.verify.oepkgs.net/api/v1/unixbench"
|
||||
local parallel="$1"
|
||||
local detail="$2"
|
||||
|
||||
local json_data=$(cat <<EOF
|
||||
{
|
||||
"os_name": "${os_name}",
|
||||
"os_version": "${os_version}",
|
||||
"os_arch": "${os_arch}",
|
||||
"cpu": ${cpu},
|
||||
"memory": ${memory},
|
||||
"parallel": ${parallel},
|
||||
"score": "${score}",
|
||||
"detail": "${detail}"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
local response=$(curl -X POST "${api_url}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "${json_data}" \
|
||||
-w "%{http_code}" \
|
||||
-o /tmp/curl_response.txt \
|
||||
-s 2>&1)
|
||||
|
||||
local curl_exit_code=$?
|
||||
local http_code="${response: -3}"
|
||||
|
||||
if [ $curl_exit_code -ne 0 ] || [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then
|
||||
LOG_INFO "发送测试结果到 API 失败 (HTTP 状态码:${http_code}, curl 退出码:${curl_exit_code}),但不影响测试流程"
|
||||
return 0
|
||||
else
|
||||
LOG_INFO "测试结果已成功发送到 API"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
LOG_INFO "基础环境准备..."
|
||||
EXECUTE_T="60m"
|
||||
cd /opt/unixbench
|
||||
LOG_INFO "开始执行 unixbench 工具 ..."
|
||||
|
||||
LOG_INFO "开始执行 ./Run -c 1"
|
||||
local result_c1=$(./Run -c 1 2>&1 | tee /dev/tty)
|
||||
if [ $? -ne 0 ]; then
|
||||
LOG_ERROR "执行 ./Run -c 1 测试失败"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
get_system_info
|
||||
parse_unixbench_result "$result_c1"
|
||||
local escaped_detail=$(escape_json_string "$result_c1")
|
||||
send_result "1" "$escaped_detail"
|
||||
|
||||
LOG_INFO "开始执行 ./Run -c $(getconf _NPROCESSORS_ONLN)"
|
||||
local result_multi=$(./Run -c $(getconf _NPROCESSORS_ONLN) 2>&1 | tee /dev/tty)
|
||||
if [ $? -ne 0 ]; then
|
||||
LOG_ERROR "执行 ./Run -c $(getconf _NPROCESSORS_ONLN) 测试失败"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
parse_unixbench_result "$result_multi"
|
||||
escaped_detail=$(escape_json_string "$result_multi")
|
||||
send_result "$(getconf _NPROCESSORS_ONLN)" "$escaped_detail"
|
||||
|
||||
}
|
||||
|
||||
function post_test() {
|
||||
LOG_INFO "Start to restore the test environment."
|
||||
DNF_REMOVE "$@"
|
||||
LOG_INFO "Finish restoring the test environment."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
1
testcases/smoke_test/smoke_openruyi/oe_test_home_directory.sh
Symbolic link
1
testcases/smoke_test/smoke_openruyi/oe_test_home_directory.sh
Symbolic link
@@ -0,0 +1 @@
|
||||
../../function_test/basic_test/basic_mugen/os-basic/oe_test_home_directory/oe_test_home_directory.sh
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Copyright (c) 2026 ISCAS .ALL rights reserved.
|
||||
# This program is licensed under Mulan PSL v2.
|
||||
# You can use it according to the terms and conditions of the Mulan PSL v2.
|
||||
# http://license.coscl.org.cn/MulanPSL2
|
||||
# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
# #############################################
|
||||
# @Author : yafen
|
||||
# @Contact : yafen@iscas.ac.cn
|
||||
# @Date : 2026-04-13
|
||||
# @License : Mulan PSL v2
|
||||
# @Desc : gcc 编译测试,编译 UnixBench
|
||||
# ############################################
|
||||
source "${OET_PATH}"/libs/locallibs/common_lib.sh
|
||||
|
||||
function pre_test() {
|
||||
LOG_INFO "Start to prepare the test environment."
|
||||
DNF_INSTALL "gcc make git"
|
||||
UNIXBENCH_DIR="/opt/UnixBench"
|
||||
LOG_INFO "End to prepare the test environment."
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
set -e
|
||||
LOG_INFO "start to run test."
|
||||
if git clone -b v6.0.0 https://github.com/kdlucas/byte-unixbench.git "${UNIXBENCH_DIR}"; then
|
||||
LOG_INFO "UnixBench 仓库克隆成功"
|
||||
cd $UNIXBENCH_DIR/UnixBench
|
||||
sed -i 's/rv64g/rva23u64/g' Makefile
|
||||
make all CC='gcc -std=gnu99'
|
||||
CHECK_RESULT $? 0 0 "compile UnixBench failed"
|
||||
else
|
||||
LOG_ERROR "UnixBench 仓库克隆失败,脚本退出"
|
||||
exit 1
|
||||
fi
|
||||
LOG_INFO "End to run test."
|
||||
set +e
|
||||
}
|
||||
|
||||
function post_test() {
|
||||
LOG_INFO "Start to restore the test environment."
|
||||
DNF_REMOVE "$@"
|
||||
rm -rf $UNIXBENCH_DIR
|
||||
LOG_INFO "Finish restoring the test environment."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,68 @@
|
||||
From 24223c0b3ca110af04e34f008943979fc6b71598 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Rix <trix@redhat.com>
|
||||
Date: Sat, 30 Dec 2023 08:58:47 -0500
|
||||
Subject: [PATCH] Fix signatures of functions
|
||||
|
||||
Signed-off-by: Tom Rix <trix@redhat.com>
|
||||
---
|
||||
foxi/onnxifi_dummy.c | 11 ++++++++---
|
||||
foxi/onnxifi_wrapper.c | 8 ++++++--
|
||||
2 files changed, 14 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/foxi/onnxifi_dummy.c b/foxi/onnxifi_dummy.c
|
||||
index 2115af9..7cc81dc 100644
|
||||
--- a/foxi/onnxifi_dummy.c
|
||||
+++ b/foxi/onnxifi_dummy.c
|
||||
@@ -103,7 +103,10 @@ ONNXIFI_PUBLIC ONNXIFI_CHECK_RESULT onnxStatus ONNXIFI_ABI onnxInitGraph(
|
||||
const void* onnxModel,
|
||||
uint32_t weightCount,
|
||||
const onnxTensorDescriptorV1* weightDescriptors,
|
||||
- onnxGraph* graph) {
|
||||
+ onnxGraph* graph,
|
||||
+ uint32_t maxSeqLength,
|
||||
+ void* deferredWeightReader) {
|
||||
+
|
||||
if (graph == NULL) {
|
||||
return ONNXIFI_STATUS_INVALID_POINTER;
|
||||
}
|
||||
@@ -215,6 +218,8 @@ ONNXIFI_PUBLIC ONNXIFI_CHECK_RESULT onnxStatus ONNXIFI_ABI
|
||||
onnxWaitEventFor(onnxEvent event,
|
||||
uint32_t timeoutMs,
|
||||
onnxEventState* eventState,
|
||||
- onnxStatus* eventStatus) {
|
||||
+ onnxStatus* eventStatus,
|
||||
+ char* message,
|
||||
+ size_t* messageLength) {
|
||||
return ONNXIFI_STATUS_SUCCESS;
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
diff --git a/foxi/onnxifi_wrapper.c b/foxi/onnxifi_wrapper.c
|
||||
index 98a9325..abe1440 100644
|
||||
--- a/foxi/onnxifi_wrapper.c
|
||||
+++ b/foxi/onnxifi_wrapper.c
|
||||
@@ -761,7 +761,9 @@ ONNXIFI_PUBLIC onnxStatus ONNXIFI_ABI onnxInitGraph(
|
||||
const void* onnxModel,
|
||||
uint32_t weightsCount,
|
||||
const onnxTensorDescriptorV1* weightDescriptors,
|
||||
- onnxGraph* graph)
|
||||
+ onnxGraph* graph,
|
||||
+ uint32_t maxSeqLength,
|
||||
+ void* deferredWeightReader)
|
||||
{
|
||||
if (graph == NULL) {
|
||||
return ONNXIFI_STATUS_INVALID_POINTER;
|
||||
@@ -797,7 +799,9 @@ ONNXIFI_PUBLIC onnxStatus ONNXIFI_ABI onnxInitGraph(
|
||||
onnxModel,
|
||||
weightsCount,
|
||||
weightDescriptors,
|
||||
- &graph_wrapper->graph);
|
||||
+ &graph_wrapper->graph,
|
||||
+ maxSeqLength,
|
||||
+ deferredWeightReader);
|
||||
switch (status) {
|
||||
case ONNXIFI_STATUS_SUCCESS:
|
||||
case ONNXIFI_STATUS_FALLBACK:
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# SPDX-FileCopyrightText: (C) 2026 Institute of Software, Chinese Academy of Sciences (ISCAS)
|
||||
# SPDX-FileCopyrightText: (C) 2026 openRuyi Project Contributors
|
||||
# SPDX-FileContributor: CHEN Xuan <chenxuan@iscas.ac.cn>
|
||||
#
|
||||
# SPDX-License-Identifier: MulanPSL-2.0
|
||||
|
||||
%global commit0 c278588e34e535f0bb8f00df3880d26928038cad
|
||||
%global date0 20260211
|
||||
%global shortcommit0 c278588
|
||||
|
||||
# Use pytorch's toolchain
|
||||
%global toolchain clang
|
||||
|
||||
Name: foxi
|
||||
Version: 0+git%{date0}.%{shortcommit0}
|
||||
Release: 1
|
||||
Summary: ONNXIFI with Facebook Extension
|
||||
License: MIT
|
||||
URL: https://github.com/houseroad/foxi
|
||||
#!RemoteAsset
|
||||
Source0: %{url}/archive/%{commit0}/%{name}-%{shortcommit0}.tar.gz
|
||||
BuildSystem: cmake
|
||||
|
||||
# https://github.com/houseroad/foxi/pull/25
|
||||
Patch0: 0001-Fix-signatures-of-functions.patch
|
||||
|
||||
BuildOption(conf): -DONNX_USE_LITE_PROTO=OFF
|
||||
|
||||
BuildRequires: cmake
|
||||
BuildRequires: clang
|
||||
|
||||
%description
|
||||
%{summary}
|
||||
|
||||
%package devel
|
||||
Summary: Headers and libraries for %{name}
|
||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||
|
||||
%description devel
|
||||
%{summary}
|
||||
|
||||
%prep -a
|
||||
# Change static library to shared
|
||||
sed -i -e 's/foxi_loader STATIC/foxi_loader SHARED/' CMakeLists.txt
|
||||
# Disable hidden so shared foxi_loader will find onnxifi_load
|
||||
sed -i -e 's/__ELF_/__NO_ELF_DISABLING_HIDDEN__/' foxi/onnxifi_loader.h
|
||||
# Fix the destination lib
|
||||
sed -i -e 's/DESTINATION lib/DESTINATION lib64/' CMakeLists.txt
|
||||
# Just install libfoxi_loader
|
||||
sed -i -e 's/foxi foxi_dummy foxi_loader/foxi_loader/' CMakeLists.txt
|
||||
# version *.so
|
||||
echo "set_target_properties(foxi_loader PROPERTIES SOVERSION \"1.4.1\")" >> CMakeLists.txt
|
||||
|
||||
# For CMake 4
|
||||
sed -i 's@cmake_minimum_required(VERSION 3.1@cmake_minimum_required(VERSION 3.5@' CMakeLists.txt
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
%exclude %{_libdir}/libfoxi.so
|
||||
%{_libdir}/libfoxi_loader.so.*
|
||||
|
||||
%files devel
|
||||
%{_includedir}/%{name}/
|
||||
%{_libdir}/libfoxi_loader.so
|
||||
|
||||
%changelog
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Copyright (c) 2026 ISCAS .ALL rights reserved.
|
||||
# This program is licensed under Mulan PSL v2.
|
||||
# You can use it according to the terms and conditions of the Mulan PSL v2.
|
||||
# http://license.coscl.org.cn/MulanPSL2
|
||||
# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
# #############################################
|
||||
# @Author : yafen
|
||||
# @Contact : yafen@iscas.ac.cn
|
||||
# @Date : 2026-04-13
|
||||
# @License : Mulan PSL v2
|
||||
# @Desc : llvm 编译测试,编译 UnixBench
|
||||
# ############################################
|
||||
source "${OET_PATH}"/libs/locallibs/common_lib.sh
|
||||
|
||||
function pre_test() {
|
||||
LOG_INFO "Start to prepare the test environment."
|
||||
DNF_INSTALL "clang cmake wget tar rpm-build dnf5-plugins"
|
||||
LOG_INFO "End to prepare the test environment."
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
set -e
|
||||
LOG_INFO "start to run test."
|
||||
BUILD_DIR="$(pwd)/build"
|
||||
rm -rf $BUILD_DIR
|
||||
mkdir -p $BUILD_DIR/SOURCES/
|
||||
if wget -P $BUILD_DIR/SOURCES/ https://github.com/houseroad/foxi/archive/c278588/foxi-c278588.tar.gz; then
|
||||
LOG_INFO "foxi-c278588.tar.gz 下载成功"
|
||||
cp 0001-Fix-signatures-of-functions.patch -p $BUILD_DIR/SOURCES/
|
||||
rpmbuild --define "_topdir $BUILD_DIR" -ba foxi.spec
|
||||
CHECK_RESULT $? 0 0 "build foxi rpm failed"
|
||||
else
|
||||
LOG_ERROR "foxi-c278588.tar.gz 下载失败,脚本退出"
|
||||
exit 1
|
||||
fi
|
||||
LOG_INFO "End to run test."
|
||||
set +e
|
||||
}
|
||||
|
||||
function post_test() {
|
||||
LOG_INFO "Start to restore the test environment."
|
||||
DNF_REMOVE "$@"
|
||||
[ -d $BUILD_DIR ] && rm -rf $BUILD_DIR
|
||||
LOG_INFO "Finish restoring the test environment."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Copyright (c) 2026 ISCAS .ALL rights reserved.
|
||||
# This program is licensed under Mulan PSL v2.
|
||||
# You can use it according to the terms and conditions of the Mulan PSL v2.
|
||||
# http://license.coscl.org.cn/MulanPSL2
|
||||
# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
# #############################################
|
||||
# @Author : yafen
|
||||
# @Contact : yafen@iscas.ac.cn
|
||||
# @Date : 2026-04-13
|
||||
# @License : Mulan PSL v2
|
||||
# @Desc : Don't allow root account to log in to the system directly using SSH
|
||||
# ############################################
|
||||
|
||||
source "$OET_PATH/libs/locallibs/common_lib.sh"
|
||||
function pre_test() {
|
||||
LOG_INFO "Start environmental preparation."
|
||||
LOG_INFO "End of environmental preparation!"
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
LOG_INFO "Start executing testcase."
|
||||
grep -qE "^\s*PermitRootLogin\s+yes" /etc/ssh/sshd_config
|
||||
CHECK_RESULT $? 1 0 "Root login should be disabled"
|
||||
expect <<EOF
|
||||
set timeout 15
|
||||
log_file testlog
|
||||
spawn ssh root@${NODE1_IPV4}
|
||||
expect {
|
||||
"*yes/no*" {
|
||||
send "yes\\r"
|
||||
}
|
||||
}
|
||||
expect {
|
||||
"password" {
|
||||
send "${NODE1_PASSWORD}\\r";
|
||||
exp_continue
|
||||
}
|
||||
}
|
||||
expect eof
|
||||
EOF
|
||||
grep "Permission denied, please try again." testlog
|
||||
CHECK_RESULT $?
|
||||
LOG_INFO "Finish testcase execution."
|
||||
}
|
||||
|
||||
function post_test() {
|
||||
LOG_INFO "Start cleanning environment."
|
||||
rm -rf testlog
|
||||
LOG_INFO "Finish environment cleanup!"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
31
testcases/smoke_test/smoke_openruyi/or_test_timedatectl.sh
Normal file
31
testcases/smoke_test/smoke_openruyi/or_test_timedatectl.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Copyright (c) 2026 ISCAS .ALL rights reserved.
|
||||
# This program is licensed under Mulan PSL v2.
|
||||
# You can use it according to the terms and conditions of the Mulan PSL v2.
|
||||
# http://license.coscl.org.cn/MulanPSL2
|
||||
# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
# #############################################
|
||||
# @Author : yafen
|
||||
# @Contact : yafen@iscas.ac.cn
|
||||
# @Date : 2026-04-13
|
||||
# @License : Mulan PSL v2
|
||||
# @Desc : Ensure clock synchronization is complete
|
||||
# ############################################
|
||||
|
||||
source "${OET_PATH}/libs/locallibs/common_lib.sh"
|
||||
|
||||
function run_test() {
|
||||
LOG_INFO "Start to run test."
|
||||
timedatectl | grep "Local time"
|
||||
CHECK_RESULT $?
|
||||
timedatectl | grep "NTP service" | grep " active"
|
||||
CHECK_RESULT $?
|
||||
LOG_INFO "End to run test."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Copyright (c) 2026 ISCAS .ALL rights reserved.
|
||||
# This program is licensed under Mulan PSL v2.
|
||||
# You can use it according to the terms and conditions of the Mulan PSL v2.
|
||||
# http://license.coscl.org.cn/MulanPSL2
|
||||
# THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
# #############################################
|
||||
# @Author : yafen
|
||||
# @Contact : yafen@iscas.ac.cn
|
||||
# @Date : 2026-04-13
|
||||
# @License : Mulan PSL v2
|
||||
# @Desc : 测试软件包的安装功能
|
||||
# ############################################
|
||||
|
||||
source "$OET_PATH/libs/locallibs/common_lib.sh"
|
||||
|
||||
function pkg_install() {
|
||||
PKG_TEST=$1
|
||||
|
||||
LOG_INFO "开始测试 ${PKG_TEST} 软件包的安装功能"
|
||||
|
||||
dnf clean all
|
||||
dnf makecache
|
||||
|
||||
# 检查是否已安装
|
||||
if dnf list installed "${PKG_TEST}" &>/dev/null; then
|
||||
LOG_INFO "检测到 ${PKG_TEST} 已安装,脚本将保持安装状态"
|
||||
INSTALLED_BEFORE=true
|
||||
else
|
||||
LOG_INFO "检测到 ${PKG_TEST} 未安装,将在测试中安装"
|
||||
INSTALLED_BEFORE=false
|
||||
fi
|
||||
|
||||
# 检查 yum 源中是否存在软件包
|
||||
LOG_INFO "检查 yum 源中是否存在 ${PKG_TEST} 软件包"
|
||||
if ! dnf list available "${PKG_TEST}" &>/dev/null; then
|
||||
LOG_ERROR "yum 源中未找到 ${PKG_TEST} 软件包"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
# 如果之前已经安装,则执行卸载步骤
|
||||
if [ "$INSTALLED_BEFORE" = true ]; then
|
||||
LOG_INFO "卸载 ${PKG_TEST} 软件包"
|
||||
dnf remove -y ${PKG_TEST}
|
||||
CHECK_RESULT $? 0 0 "卸载 ${PKG_TEST} 失败"
|
||||
LOG_INFO "环境已恢复到未安装状态"
|
||||
fi
|
||||
|
||||
LOG_INFO "执行安装 ${PKG_TEST} 软件包"
|
||||
dnf install -y ${PKG_TEST} --refresh
|
||||
CHECK_RESULT $? 0 0 "安装 ${PKG_TEST} 失败"
|
||||
|
||||
# 验证安装是否成功
|
||||
LOG_INFO "验证 ${PKG_TEST} 安装是否成功"
|
||||
if dnf list installed ${PKG_TEST} &>/dev/null; then
|
||||
LOG_INFO "${PKG_TEST} 安装验证成功"
|
||||
else
|
||||
LOG_ERROR "${PKG_TEST} 安装验证失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证卸载功能
|
||||
LOG_INFO "卸载 ${PKG_TEST} 软件包"
|
||||
dnf remove -y ${PKG_TEST}
|
||||
CHECK_RESULT $? 0 0 "卸载 ${PKG_TEST} 失败"
|
||||
|
||||
# 环境恢复:如果之前已安装,则重新安装软件包
|
||||
if [ "$INSTALLED_BEFORE" = true ]; then
|
||||
LOG_INFO "恢复环境:安装 ${PKG_TEST} 软件包"
|
||||
dnf install -y ${PKG_TEST}
|
||||
CHECK_RESULT $? 0 0 "安装 ${PKG_TEST} 失败"
|
||||
LOG_INFO "环境已恢复到已安装状态"
|
||||
else
|
||||
LOG_INFO "保持 ${PKG_TEST} 未安装状态"
|
||||
fi
|
||||
INSTALLED_BEFORE=""
|
||||
LOG_INFO "${PKG_TEST} 软件包安装功能测试完成"
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
set -e
|
||||
if [ -n "$PKG_INSTALL" ]; then
|
||||
echo "优先使用环境变量 PKG_INSTALL: $PKG_INSTALL"
|
||||
echo "$PKG_INSTALL" | tr ',' '\n' | while read -r pkg; do
|
||||
[ -n "$pkg" ] && pkg_install "$pkg"
|
||||
done
|
||||
else
|
||||
echo "环境变量未设置,使用默认文件路径"
|
||||
FILE_PATH="$OET_PATH/.os-autotest/pkg-install"
|
||||
if [ -f "$FILE_PATH" ]; then
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] && pkg_install "$line"
|
||||
done < "$FILE_PATH"
|
||||
else
|
||||
LOG_ERROR "文件路径不存在: $FILE_PATH"
|
||||
fi
|
||||
fi
|
||||
set +e
|
||||
}
|
||||
|
||||
function post_test() {
|
||||
if [ -z "$PKG_TEST" ]; then
|
||||
return
|
||||
fi
|
||||
if [ "$INSTALLED_BEFORE" = true ]; then
|
||||
LOG_INFO "恢复环境:安装 ${PKG_TEST} 软件包"
|
||||
dnf install -y ${PKG_TEST} --refresh
|
||||
CHECK_RESULT $? 0 0 "安装 ${PKG_TEST} 失败"
|
||||
LOG_INFO "环境已恢复到已安装状态"
|
||||
elif [ "$INSTALLED_BEFORE" = false ]; then
|
||||
if dnf list installed "${PKG_TEST}" &>/dev/null; then
|
||||
LOG_INFO "清理环境:卸载 ${PKG_TEST} 软件包"
|
||||
dnf remove -y ${PKG_TEST}
|
||||
CHECK_RESULT $? 0 0 "卸载 ${PKG_TEST} 失败"
|
||||
LOG_INFO "环境已恢复到未安装状态"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
INSTALLED_BEFORE=""
|
||||
PKG_TEST=""
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user