Repository navigation
test: add unit tests for deviceinfo ThreadPoolTask/ThreadPool/MainJob/DeviceInterface - #930
Conversation
|
Warning
详情 {
"lshw": {
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPool.cpp": [
" * B1: lshw appended to both lists, canNotReplace=false",
" // Act \u2014 find lshw entry in both lists",
" if (c.file == \"lshw.txt\")",
" EXPECT_EQ(std::count_if(pool->m_ListCmd.cbegin(), pool->m_ListCmd.cend(), [](const Cmd &c) { return c.file == \"lshw.txt\"; }), 1);",
" // Act \u2014 lshw cmd redirects to PATH/lshw.txt",
" // Act \u2014 m_ListCmd: lshw + 9 dmidecode + upower + lscpu + lsblk + ls_sg + lspci +",
" // Act \u2014 m_ListUpdate: lshw + upower + lscpu + lsblk + ls_sg + lspci + lpstat +"
],
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPoolTask.cpp": [
" ThreadPoolTask task(\"lshw > f\", \"ut_r2f_cnr.txt\", true, -1);",
" task.runCmdToFile(\"lshw > f\"); // branch: CanNotReplace && exists -> return",
" ThreadPoolTask task(\"lshw > f\", \"ut_r2f_rep.txt\", false, -1);",
" task.runCmdToFile(\"lshw > f\"); // branch: replace allowed -> runCmd(cmd)",
" EXPECT_EQ(ut_tt_runCmd1Calls, QStringList() << QString(\"lshw > f\"));"
]
},
"dmidecode": {
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPool.cpp": [
" * B2: dmidecode_spn appended to m_ListCmd only, canNotReplace=true",
" // Act \u2014 m_ListCmd contains dmidecode-only entries not in m_ListUpdate",
" if (c.file == \"dmidecode_spn.txt\")",
" EXPECT_EQ(std::count_if(pool->m_ListCmd.cbegin(), pool->m_ListCmd.cend(), [](const Cmd &c) { return c.file == \"dmidecode_spn.txt\"; }), 1);",
" EXPECT_EQ(std::count_if(pool->m_ListUpdate.cbegin(), pool->m_ListUpdate.cend(), [](const Cmd &c) { return c.file == \"dmidecode_spn.txt\"; }), 0);",
" // Act \u2014 m_ListCmd: lshw + 9 dmidecode + upower + lscpu + lsblk + ls_sg + lspci +"
]
}
} |
Reviewer's GuideAdds or rewrites four Google Test suites for ThreadPoolTask, ThreadPool, MainJob, and DeviceInterface, using deterministic stubs for system and D-Bus dependencies to provide 133 focused tests and 100% function coverage with 92.0% line coverage; the reported single failing test is documented as pre-existing outside this PR. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning
详情 {
"lshw": {
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPool.cpp": [
" * B1: lshw appended to both lists, canNotReplace=false",
" // Act \u2014 find lshw entry in both lists",
" if (c.file == \"lshw.txt\")",
" EXPECT_EQ(std::count_if(pool->m_ListCmd.cbegin(), pool->m_ListCmd.cend(), [](const Cmd &c) { return c.file == \"lshw.txt\"; }), 1);",
" // Act \u2014 lshw cmd redirects to PATH/lshw.txt",
" // Act \u2014 m_ListCmd: lshw + 9 dmidecode + upower + lscpu + lsblk + ls_sg + lspci +",
" // Act \u2014 m_ListUpdate: lshw + upower + lscpu + lsblk + ls_sg + lspci + lpstat +"
],
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPoolTask.cpp": [
" ThreadPoolTask task(\"lshw > f\", \"ut_r2f_cnr.txt\", true, -1);",
" task.runCmdToFile(\"lshw > f\"); // branch: CanNotReplace && exists -> return",
" ThreadPoolTask task(\"lshw > f\", \"ut_r2f_rep.txt\", false, -1);",
" task.runCmdToFile(\"lshw > f\"); // branch: replace allowed -> runCmd(cmd)",
" EXPECT_EQ(ut_tt_runCmd1Calls, QStringList() << QString(\"lshw > f\"));"
]
},
"dmidecode": {
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPool.cpp": [
" * B2: dmidecode_spn appended to m_ListCmd only, canNotReplace=true",
" // Act \u2014 m_ListCmd contains dmidecode-only entries not in m_ListUpdate",
" if (c.file == \"dmidecode_spn.txt\")",
" EXPECT_EQ(std::count_if(pool->m_ListCmd.cbegin(), pool->m_ListCmd.cend(), [](const Cmd &c) { return c.file == \"dmidecode_spn.txt\"; }), 1);",
" EXPECT_EQ(std::count_if(pool->m_ListUpdate.cbegin(), pool->m_ListUpdate.cend(), [](const Cmd &c) { return c.file == \"dmidecode_spn.txt\"; }), 0);",
" // Act \u2014 m_ListCmd: lshw + 9 dmidecode + upower + lscpu + lsblk + ls_sg + lspci +"
]
}
} |
deepin pr auto review🤖 AI 代码审查报告📊 总体评价
🔍 详细分析1. 语法逻辑 ✅评价: 语法正确,逻辑清晰 ✅ 通过 潜在问题: 建议: ['Constructor_AfterInit_CreatesDeviceInfoDirectory:Arrange 阶段先删除 PATH 目录、Act 段不再调用 mkpath,仅依赖构造函数的 mkdir,再断言 exists,使测试真正验证副作用', 'ut_mainjob.cpp 中 ut_mj_msleepMs 比较统一使用 1000ul,避免 unsigned int/unsigned long 宽度差异告警'] 2. 代码质量 ✅评价: 代码结构清晰,注释完整 ✅ 通过 潜在问题: 建议: ['统一在所有测试 fixture 的 TearDown 中清理 DeviceInfoManager 单例状态(或在 DeviceInfoManager 增加 public clear()/reset() 方法供测试使用),保证测试隔离', 'dlsym 失败时改用 ADD_FAILURE()/GTEST_FAIL 并返回空 PMF 或抛异常,避免 abort 终止整个二进制;调用方校验 PMF 有效性', 'ut_ThreadPool.cpp 显式 #include ', "删除或解释 '// DBG_STUB_INVOKE' 标记注释", '移除未使用的死变量,或补全对应断言', '为 pmfFromSymbol 的 memcpy 增加 static_assert(sizeof(T) >= sizeof(void*)) 编译期守护'] 3. 代码性能 ✅评价: 性能良好,资源使用合理 ✅ 通过 潜在问题: 建议: ['ut_ThreadPoolTask.cpp 可在 TearDown 增加 QDir(PATH).removeRecursively() 清理测试产生的临时文件,避免反复运行后 /tmp/device-info 残留文件累积'] 4. 代码安全 🔒评价: 存在0个安全漏洞 ✅ 通过
安全漏洞详情: 建议: ['无安全相关改进建议'] 💡 改进建议代码示例// ut_ThreadPool.cpp — 显式包含 <algorithm> 并清理单例状态
#include <gtest/gtest.h>
#include <QProcess>
#include <QDir>
#include <algorithm> // 显式包含,避免传递依赖
#include "threadpool.h"
#include "threadpooltask.h"
#include "deviceinfomanager.h"
#include "DDLog.h"
#include "../stub.h"
#define private public
#include "deviceinfomanager.h"
#undef private
class ThreadPool_UT : public ::testing::Test
{
public:
Stub stub;
ThreadPool *pool = nullptr;
void SetUp() override
{
ut_tp_resetState();
DeviceInfoManager::getInstance()->m_MapInfo.clear(); // 统一清理单例
stub.set(ut_tp_startFn, ut_tp_poolStart);
stub.set(ut_tp_procStartFn, ut_tp_procStart);
stub.set(ADDR(QProcess, waitForFinished), ut_tp_waitFinished);
stub.set(ADDR(QProcess, readAllStandardOutput), ut_tp_readOut);
QDir().mkpath(PATH);
pool = new ThreadPool();
}
void TearDown() override
{
delete pool;
pool = nullptr;
DeviceInfoManager::getInstance()->m_MapInfo.clear(); // 统一清理单例
stub.reset(ADDR(QProcess, readAllStandardOutput));
stub.reset(ADDR(QProcess, waitForFinished));
stub.reset(ut_tp_procStartFn);
stub.reset(ut_tp_startFn);
}
};
// ut_mainjob.cpp — dlsym 失败时优雅失败而非 abort
template <typename T>
static T ut_mj_pmfFromSymbol(const char *mangled)
{
void *addr = dlsym(RTLD_DEFAULT, mangled);
if (!addr) {
ADD_FAILURE() << "dlsym failed for " << mangled;
return T{}; // 返回空 PMF,调用方应校验
}
static_assert(sizeof(T) >= sizeof(void *), "PMF layout assumption violated");
T pmf;
std::memset(&pmf, 0, sizeof(pmf));
std::memcpy(&pmf, &addr, sizeof(void *));
return pmf;
}本报告由 AI 代码审查工具自动生成 |
…iceInterface GTest suites 重写 server 端 loadinfo 四个类的单元测试并补齐 DeviceInterface: - ut_ThreadPoolTask.cpp:重写 59 用例,覆盖 15 方法(ctor/run/runCmd/ runCmdToCache/runCmdToFile/loadCpuInfo 及全部 load*ToCache/ToFile 解析器), 重定向/管道/通配符分支与智能谓词解析全覆盖 - ut_ThreadPool.cpp:重写 26 用例,覆盖 initCmd 全部分支(15 段命令模板) - ut_mainjob.cpp:重写 18 用例,覆盖 ctor/updateAllDevice/slotUsbChanged/ executeClientInstruction/setWorkingFlag,单例计数器跨用例隔离 - ut_DeviceInterface.cpp:新增 20 用例,覆盖 getInfo/refreshInfo/ getGpuInfoForFTDTM/getGpuMemInfoForFTDTM 单位换算/setMonitorDeviceFlag 授权分支 - stub 要点:QThreadPool::start 按自动删除语义释放;QFile::open/exists 与 QIODevice::readAll 为虚函数,取址得到 vtable 索引编码的 pmf,改用 dlsym 解析真实代码地址构造 pmf 后再 prologue 打桩 - 外部依赖(QProcess/DBus/文件系统/sysfs)全部 stub,不依赖真实设备环境; DeviceInfoManager 单例在 SetUp/TearDown 用 m_MapInfo.clear() 隔离 - 合跑 323/324 PASSED(唯一失败 CoreCpu_UT.LogicalIsExisted_NegativeCoreId 为基线 6ccddaf 既有失败,经 git stash 验证与本批改动无关,用例前提 与 logicalIsExisted 语义不符,留待后续批次修正)
…t tiered coverage to gates Mode 2/3 coverage completion for deepin-deviceinfo (ut-t29 worktree): - ut_mainjob.cpp (+9 cases): getVersion (file unopenable / Major-Minor parsing), initDriverRepoSource (pro-driver early return / device repo exists / open fail), slotDriverControl (success triggers DETECT / failure no-op), slotWakeupHandle (singleShot deferral), sqlCopytoKernel (disableInDevice + hwinfo probe persisted via stubbed QProcess and ControlInterface) - ut_DeviceInterface.cpp (+1 case): getUserAuthorPasswd real body under DISABLE_POLKIT (stub released locally, re-armed after) - QFile::open / QIODevice::readAll / static QFile::exists / QProcess stubbed via dlsym-resolved pmfs; no real file or subprocess touched - self-check structural: 0 errors (ut_mainjob 0/0, DeviceInterface 0 errors 1 benign SOLE_BOOL warning) - coverage (gcov tracefile, lcov unavailable in env): high 91.6% line / 100% fn, mid 92.5% / 100%, low 94.7% / 100%, total 92.0% line - all tiered gates pass - test results: 334 cases / 20 suites / 333 passed; sole failure CoreCpu_UT.LogicalIsExisted_NegativeCoreId_ReturnsFalse is pre-existing on base 6ccddaf (out of scope, documented in tests/.ut/defects.json) - mode 5 defect export: tests/.ut/defects.json + defects-summary.md (1 test defect, 0 source defects)
|
Warning
详情 {
"lshw": {
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPool.cpp": [
" * B1: lshw appended to both lists, canNotReplace=false",
" // Act \u2014 find lshw entry in both lists",
" if (c.file == \"lshw.txt\")",
" EXPECT_EQ(std::count_if(pool->m_ListCmd.cbegin(), pool->m_ListCmd.cend(), [](const Cmd &c) { return c.file == \"lshw.txt\"; }), 1);",
" // Act \u2014 lshw cmd redirects to PATH/lshw.txt",
" // Act \u2014 m_ListCmd: lshw + 9 dmidecode + upower + lscpu + lsblk + ls_sg + lspci +",
" // Act \u2014 m_ListUpdate: lshw + upower + lscpu + lsblk + ls_sg + lspci + lpstat +"
],
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPoolTask.cpp": [
" ThreadPoolTask task(\"lshw > f\", \"ut_r2f_cnr.txt\", true, -1);",
" task.runCmdToFile(\"lshw > f\"); // branch: CanNotReplace && exists -> return",
" ThreadPoolTask task(\"lshw > f\", \"ut_r2f_rep.txt\", false, -1);",
" task.runCmdToFile(\"lshw > f\"); // branch: replace allowed -> runCmd(cmd)",
" EXPECT_EQ(ut_tt_runCmd1Calls, QStringList() << QString(\"lshw > f\"));"
]
},
"dmidecode": {
"deepin-devicemanager-server/tests/src/LoadInfo/ut_ThreadPool.cpp": [
" * B2: dmidecode_spn appended to m_ListCmd only, canNotReplace=true",
" // Act \u2014 m_ListCmd contains dmidecode-only entries not in m_ListUpdate",
" if (c.file == \"dmidecode_spn.txt\")",
" EXPECT_EQ(std::count_if(pool->m_ListCmd.cbegin(), pool->m_ListCmd.cend(), [](const Cmd &c) { return c.file == \"dmidecode_spn.txt\"; }), 1);",
" EXPECT_EQ(std::count_if(pool->m_ListUpdate.cbegin(), pool->m_ListUpdate.cend(), [](const Cmd &c) { return c.file == \"dmidecode_spn.txt\"; }), 0);",
" // Act \u2014 m_ListCmd: lshw + 9 dmidecode + upower + lscpu + lsblk + ls_sg + lspci +"
]
}
} |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: add-uos, lzwind The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
/forcemerge |
|
This pr force merged! (status: unstable) |
Summary
Add/rewrite Google Test suites for the server device-info module (deepin-devicemanager-server/deepin-deviceinfo/src), covering ThreadPoolTask / ThreadPool / MainJob / DeviceInterface, plus full coverage instrumentation and tiered coverage reporting.
Test scope and counts
Total in-scope: 4 classes / 133 test cases (pre-existing suites untouched; binary total 334 cases / 20 suites).
Build & run results
CoreCpu_UT.LogicalIsExisted_NegativeCoreId_ReturnsFalseis pre-existing on base 6ccddaf (verified via git stash; out of this task's scope)Coverage summary (gcov tracefile; lcov unavailable in env)
Tiered gates (line / function) all pass:
Uncovered functions: none (39/39 inventory methods matched and called; remaining lines are timer-deferred lambdas and root-owned-path branches exercised via stubs).
Defect report (Mode 5)
CoreCpu_UT.LogicalIsExisted_NegativeCoreId_ReturnsFalse— the case inserts id 0 then assertslogicalIsExisted(0)is false, contradicting the plain map-find implementation atcorecpu.cpp:40. Details + suggested fix intests/.ut/defects.json/defects-summary.md(uploaded to the issue).Stubbing strategy
External dependencies (DBus, QFile, QProcess, QThread, timers, sysfs) are fully stubbed — tests never touch the real system. Virtual member functions (QFile::open, QIODevice::readAll) are stubbed via dlsym-resolved pmfs (prologue patching with
&Class::methodaddresses is unsafe for virtuals — vtable-index-encoded, not code addresses).Commits
0f04cce6test(LoadInfo): rewrite ThreadPoolTask/ThreadPool/MainJob and add DeviceInterface GTest suites6036734atest(LoadInfo): cover remaining MainJob/DeviceInterface branches, lift tiered coverage to gatesSummary by Sourcery
Strengthen server device-info regression protection by adding isolated unit tests for the core device-loading, monitoring, caching, and interface workflows.
New Features:
Enhancements:
Tests: