Skip to content

Conversation

unicornx
Copy link
Contributor

@unicornx unicornx commented Jul 24, 2025

具体需求来源参考:#10513

本 PR 是本工作的第一步,主要做了如下工作:

将 utest 的 Kconfig 的入口从 examples/utest/testcases/Kconfig 改为 Kconfig.utestcases。单元测试对于内核来说是一个非常重要的模块,放在 examples 下不合适。

以后的 utest 的 testcase 源码会分别放到各个模块下自己维护,但是 Kconfig 的入口会放在 Kconfig.utestcases 中统一维护。这样在执行诸如 menuconfig 时可以统一从一个地方进入进行配置,避免在 menuconfig 界面中到处寻找 utest 的配置开关。

对于各个模块来说,以后可以按照如下方式统一维护单元测试用例:

  • 在自己的模块所在目录下新建一个名为 utest 的子目录
  • 在 utest 子目录中存放以下文件:
    • 本模块的单元测试用例程序代码 c 文件。
    • Kconfig 文件,为本模块的单元测试文件增加配置选项,推荐选项命名为 RT_UTEST_TC_USING_XXXX,XXXX 为本模块的全局唯一模块名。
    • SConscript 文件,注意在增加 src 文件时,除了依赖于 RT_UTEST_TC_USING_XXXX 还要依赖 RT_UTEST_USING_ALL_CASES,两者是 or 的关系。RT_UTEST_USING_ALL_CASES 的作用是一旦打开这个选项,则所有的单元测试都会启用,避免逐个选择。

目前整个内核源码树下基于 utest 框架实现的单元测试,除了 examples/utest/testcases 外,只有 components/drivers/audio/utest/src/klibc/utest/ 两处,本 PR 将这两处的 Kconfig 选项也集成到 Kconfig.utestcases 下。

注意:本 PR 并没有将 examples/utest/testcases 下的 c 源码挪到他们该属于的模块下去,这部分工作将作为后续工作逐渐展开。

本 PR 为方便 review,分为三个 commit:

  • ”utest: move entry from examples to utest“:将 utest 的 Kconfig 的入口从 examples/utest/testcases/Kconfig 改为 Kconfig.utestcases
  • ”utest: integrate config option for utest of klibc“:将 src/klibc/utest/ 的 Kconfig 选项也集成到 Kconfig.utestcases 下。
  • ”utest: integrate config option for utest of audio driver“: 将 components/drivers/audio/utest/ 的 Kconfig 选项也集成到 Kconfig.utestcases 下。

@unicornx
Copy link
Contributor Author

@Yaochenger @kurisaW 请 review。

@unicornx unicornx requested a review from kurisaW July 24, 2025 09:40
Copy link

github-actions bot commented Jul 24, 2025

📌 Code Review Assignment

🏷️ Tag: components

Reviewers: @Maihuanyi

Changed Files (Click to expand)
  • components/drivers/audio/Kconfig
  • components/drivers/audio/utest/Kconfig

🏷️ Tag: kernel

Reviewers: @GorrayLi @ReviewSun @hamburger-os @lianux-mm @wdfk-prog @xu18838022837

Changed Files (Click to expand)
  • src/klibc/Kconfig
  • src/klibc/utest/Kconfig

📊 Current Review Status (Last Updated: 2025-08-25 16:39 CST)


📝 Review Instructions

  1. 维护者可以通过单击此处来刷新审查状态: 🔄 刷新状态
    Maintainers can refresh the review status by clicking here: 🔄 Refresh Status

  2. 确认审核通过后评论 LGTM/lgtm
    Comment LGTM/lgtm after confirming approval

  3. PR合并前需至少一位维护者确认
    PR must be confirmed by at least one maintainer before merging

ℹ️ 刷新CI状态操作需要具备仓库写入权限。
ℹ️ Refresh CI status operation requires repository Write permission.

@kurisaW kurisaW requested a review from mysterywolf July 24, 2025 09:43
@kurisaW
Copy link
Member

kurisaW commented Jul 24, 2025

如果不支持相对路径的写法的话,建议可以使用环境变量,例如类似:

rsource "$RTT_DIR/examples/utest/testcases/utest/Kconfig"
image

@unicornx unicornx force-pushed the dev-utest-framework branch from a15c073 to 84bad87 Compare July 24, 2025 12:32
@unicornx
Copy link
Contributor Author

如果不支持相对路径的写法的话,建议可以使用环境变量,例如类似:

rsource "$RTT_DIR/examples/utest/testcases/utest/Kconfig"

改了,但是 ci 又报了其他的错误 :(

@Yaochenger
Copy link
Contributor

修改建议:
举例:原来的实现:

rsource "$RTT_DIR/examples/utest/testcases/utest/Kconfig"

建议修改为:

source "$(RTT_DIR)/examples/utest/testcases/utest/Kconfig"

rsource "$RTT_DIR替换为source "$(RTT_DIR)
使用当前提交的分支在本地menuconfig出现CI同样问题,修改后可正常使用。

@unicornx
Copy link
Contributor Author

修改建议: 举例:原来的实现:

rsource "$RTT_DIR/examples/utest/testcases/utest/Kconfig"

建议修改为:

source "$(RTT_DIR)/examples/utest/testcases/utest/Kconfig"

rsource "$RTT_DIR替换为source "$(RTT_DIR) 使用当前提交的分支在本地menuconfig出现CI同样问题,修改后可正常使用。

改了又出现原先最初的错误:
da505485536ad54abc5dc68fe2d4d8c
是不是 github 上运行时的 kconfiglib 的版本不一样啊?
我这里本地是 Version: 14.1.0

@unicornx unicornx closed this Jul 25, 2025
@unicornx unicornx force-pushed the dev-utest-framework branch from 7be5936 to d23006e Compare July 25, 2025 02:58
@unicornx unicornx reopened this Jul 25, 2025
@unicornx unicornx force-pushed the dev-utest-framework branch 3 times, most recently from 1d38849 to 92aa975 Compare July 25, 2025 07:35
@unicornx
Copy link
Contributor Author

unicornx commented Jul 25, 2025

我发现导致 dist 的 ci 失败的原因是在于运行 scons --dist 时会执行 MkDist,并触发 tools/mkdist.py 中的 bsp_update_kconfig_testcases 函数,这个函数的代码如下:

def bsp_update_kconfig_testcases(dist_dir):
    # delete testcases in rt-thread/Kconfig
    if not os.path.isfile(os.path.join(dist_dir, 'rt-thread/Kconfig')):
        return

    with open(os.path.join(dist_dir, 'rt-thread/Kconfig'), 'r') as f:
        data = f.readlines()
    with open(os.path.join(dist_dir, 'rt-thread/Kconfig'), 'w') as f:
        for line in data:
            if line.find('examples/utest/testcases/Kconfig') == -1:
                f.write(line)

会跳过 'examples/utest/testcases/Kconfig 这一行生成 dist/project 中的 Kconfig 文件。这个 PR 的 ci check 失败就是因为,我们改了 Kconfig 中的 rsource 的文件路径,导致 bsp_update_kconfig_testcases 不起效果(仍然 rsource 了一个 example 下的 Kconfig),而 dist 后的 dist/project/rt-thread/ 去掉了 example 目录。 导致 ci check 运行 Project dist Tools 检查时发现路径不存在。解决方法是,这里的 'examples/utest/testcases/Kconfig 换成本 PR 中 Kconfig 里的 "components/utilities/utest/Kconfig" 即可。
P.S. 这个问题其实本地运行 dist 也会看到,和 ci 环境没有关系, 复现步骤如下。

cd bsp/stm32/stm32f407-atk-explorer/
scons --dist
cd dist/project/rt-thread/
scons --menuconfig
scons: Reading SConscript files ...
menuconfig: rt-thread/components/utilities/utest/Kconfig:10: 'rt-thread/components/utilities/utest/../../../examples/utest/testcases/utest/Kconfig' not found (in 'rsource "../../../examples/utest/testcases/utest/Kconfig"'). Check that environment variables are set correctly (e.g. $srctree, which is unset or blank). Also note that unset environment variables expand to the empty string.

但具体原因不知道是否有人可以解释一下, dist 中这里这么做的目的是什么,我发现在 dist 后的 dist/project/rt-thread/ 去掉了 example 目录,而 utest 的那些 utestcase 全部是在 example 下,我猜测这是原来代码中要去掉 rsource "examples/utest/testcases/Kconfig" 的原因。

这实际上存在一个悖论,就是以后 utest 的内容我们在 dist 中是否需要保留?因为以后的设计思路是 utest 的 testcase 都会放到各个模块自己的目录下,不像现在都是放在 example 的 utest 下,所以我不清楚当时设计 dist 时是怎么考虑这个问题的。如果沿袭原来的思路,utest 的testcase 是不参与 dist 的,但是按照我现在的思路,utest 作为每个模块的组成部分,和 example 不是一回事情。dist 时我理解是需要和模块一起打包的。

此外,我发现和 bsp_update_kconfig_testcases 类似的处理还有一处,就是 tools/env_utility.py 中的 exclude_utestcases 函数。摘录如下:

# Exclude utestcases
def exclude_utestcases(RTT_ROOT):
    if os.path.isfile(os.path.join(RTT_ROOT, 'examples/utest/testcases/Kconfig')):
        return

    if not os.path.isfile(os.path.join(RTT_ROOT, 'Kconfig')):
        return

    with open(os.path.join(RTT_ROOT, 'Kconfig'), 'r') as f:
        data = f.readlines()
    with open(os.path.join(RTT_ROOT, 'Kconfig'), 'w') as f:
        for line in data:
            if line.find('examples/utest/testcases/Kconfig') == -1:
                f.write(line)

这里也有类似的逻辑,搜索 exclude_utestcases 的调用处,分别是在 tools/env_utility.py 中的 menuconfig/guiconfig/defconfig 三处,目前还不清楚这里是何目的?

@kurisaW
Copy link
Member

kurisaW commented Jul 25, 2025

我个人猜测example原本的目的是不应该参与构建的(除了utest目录,其余似乎看起来都没有加构建脚本),仅作为一个参考设计,因此在dist中会被排除构建,所以起初utest被放到example中就是不合理的,建议直接放到如下路径,后面再慢慢推动utest的分布式构建:

components/utilities/utest

另外针对你的解决方法,我持赞同意见:

解决方法是,这里的 'examples/utest/testcases/Kconfig 换成本 PR 中 Kconfig 里的 "components/utilities/utest/Kconfig" 即可。

@unicornx unicornx marked this pull request as draft July 25, 2025 08:29
@unicornx unicornx marked this pull request as ready for review July 25, 2025 08:30
@unicornx unicornx marked this pull request as draft July 25, 2025 08:31
@Rbb666
Copy link
Member

Rbb666 commented Jul 30, 2025

我个人猜测example原本的目的是不应该参与构建的(除了utest目录,其余似乎看起来都没有加构建脚本),仅作为一个参考设计,因此在dist中会被排除构建,所以起初utest被放到example中就是不合理的,建议直接放到如下路径,后面再慢慢推动utest的分布式构建:

components/utilities/utest

另外针对你的解决方法,我持赞同意见:

解决方法是,这里的 'examples/utest/testcases/Kconfig 换成本 PR 中 Kconfig 里的 "components/utilities/utest/Kconfig" 即可。

我也同意这种改法,将example中的部分逐渐分布到各个目录下面,dist出的工程也可也保留测试用例内容

Change the entry of utest's Kconfig from
'examples/utest/testcases/Kconfig' to
'Kconfig.utestcases'.

Modified the build scripts where the path name
is "examples/utest/testcases/Kconfig" and changed
it to 'Kconfig.utestcases', otherwise build
operations such 'scons --dist' may fail.

In the future, the testcase source code of
utest will be placed in each module for
maintenance, but the entry of Kconfig will all
be placed in Kconfig.utestcases for unified
maintenance. In this way, when executing menuconfig,
people can enter and configure from one place,
avoiding searching for utest configuration switches
here and there in the menuconfig interface.

For each module, you can maintain unit-test
in a unified manner in the following way:
- Create a subdirectory named 'utest' in the
  directory where your module is located.
- Store the following files in the utest subdirectory:
  - Unit test case program source code files for this
    module.
  - Kconfig file, add configuration options for the
    unit test files of this module, the recommended
    option is named RT_UTEST_TC_USING_XXXX, XXXX is the
    global unique module name of this module.
  - SConscript file, note that when adding src files,
    in addition to relying on RT_UTEST_TC_USING_XXXX,
    you must also rely on RT_UTEST_USING_ALL_CASES, the
    two dependencies are in an "or" relationship. The
    role of RT_UTEST_USING_ALL_CASES is that once this
    option is turned on, all unit tests will be enabled
    to avoid selecting one by one.

After completing the above steps, add the path of the
Kconfig file of utest of this module to the
Kconfig.utestcases file.

Signed-off-by: Chen Wang <[email protected]>
@unicornx unicornx force-pushed the dev-utest-framework branch from 92aa975 to 7f72449 Compare August 25, 2025 08:39
@github-actions github-actions bot added the tools label Aug 25, 2025
@unicornx unicornx marked this pull request as ready for review August 25, 2025 08:42
@unicornx
Copy link
Contributor Author

@kurisaW @Rbb666 @Yaochenger 我改了第二版,请 review, 现在 ci check 没问题了。

@unicornx
Copy link
Contributor Author

@Rbb666 merge 时最好保留 3 个 commit,不要压缩,谢谢

@kurisaW
Copy link
Member

kurisaW commented Aug 25, 2025

Kconfig.utestcases放到根目录下看起来感觉会不会不太美观啊,也不规范,我还是保留之前的想法,bsp_update_kconfig_testcases和exclude_utestcases可以删掉或者给注释掉,然后:

'examples/utest/testcases/Kconfig 换成本 PR 中 Kconfig 里的 "components/utilities/utest/Kconfig" 即可。

dist的工程我觉得保留utest是没有影响的,对我来说是希望存在的,唯一来说目前可以看得到的影响就是需要在链接段加入utest的代码段,这个感觉影响不大

@unicornx
Copy link
Contributor Author

Kconfig.utestcases放到根目录下看起来感觉会不会不太美观啊,也不规范,我还是保留之前的想法,bsp_update_kconfig_testcases和exclude_utestcases可以删掉或者给注释掉,然后:

'examples/utest/testcases/Kconfig 换成本 PR 中 Kconfig 里的 "components/utilities/utest/Kconfig" 即可。

dist的工程我觉得保留utest是没有影响的,对我来说是希望存在的,唯一来说目前可以看得到的影响就是需要在链接段加入utest的代码段,这个感觉影响不大

我原来是放在 components/utilities/utest/Kconfig 下的,但是后来改成了 Kconfig.utestcases 是有原因的,陈述如下:

每个模块的 Kconfig 应该负责本模块的配置定义,所以 components/utilities/utest/Kconfig 的意思应该是 utest 这个模块(注意 utest 不是 unit testcase,是一个用于 unit test 的 framework 软件模块)的配置选项。而我们现在需要的是一个定义哪些模块的 unit testcases 需要加入 RT-thread 的主菜单这么一件事情,所以用 components/utilities/utest/Kconfig 是不合适的。

所以我们现在实际上是需要定义一个 RTT 全局的单元测试集合的条目表,这是一个非常 high level 的 Kconfig,所以我觉得放在 RTT 的根目录下其实并不过分,原来我曾经考虑在 RTT 根目录下建一个目录 utestcases 下面放一个 Kconfig 文件,即 utestcases/Kconfig 但觉得多此一举,因为这个 utestcases 目录下其实不会有其他文件了。所以我定义了一个 Kconfig.utestcases 文件。我不清楚 RTT 的规范是什么,其实 kconfig 框架下只要有一个总入口 Kconfig 就可以了,其他 sourse 进来的文件并不一定也得叫 KCofnig 吧?

另外你说的 bsp_update_kconfig_testcases和exclude_utestcases可以删掉或者给注释掉 这个怕是不行,原因我在上面分析过了,对于 dist 来说,它在打包过程中会删掉 examples 这个目录,所以原来 dist 过程中需要通过移除 Kconfig 中的 rsource "examples/utest/testcases/Kconfig" 这一行。而现在同样要移除 Kconfig 中的 rsource Kconfig.utestcases 这一行,因为 Kconfig,utestcases 文件中会 rsource "examples/utest/testcases/utest/Kconfig" 等, examples 目录被 dist 删除后同样会导致这里失败。我的计划是目前保留 bsp_update_kconfig_testcasesexclude_utestcases 这个函数,只是把这个函数中删除 rsource "examples/utest/testcases/Kconfig" 这一行改成删除 rsource Kconfig.utestcases 这一行。等以后我们把 example 目录下所有的测试用例代码都移到其他目录下后,这时候才可以彻底地删除 bsp_update_kconfig_testcasesexclude_utestcases 这个函数以及调用他们的地方。

@unicornx
Copy link
Contributor Author

@kurisaW

Kconfig.utestcases放到根目录下看起来感觉会不会不太美观啊,也不规范,我还是保留之前的想法,

另外补充一下,将 Kconfig.utestcases 放到 RTT 源码根目录下还有一个好处就是写 rsource 的相对路径时不用写很多 ”../", 原来放在 components/utilities/utest/Kconfig 时都得写成:rsource "../../../xxxxxxx" 看上去很不美观。

@ReviewSun
Copy link
Contributor

LGTM

@kurisaW
Copy link
Member

kurisaW commented Aug 26, 2025

Kconfig.utestcases放到根目录下看起来感觉会不会不太美观啊,也不规范,我还是保留之前的想法,bsp_update_kconfig_testcases和exclude_utestcases可以删掉或者给注释掉,然后:
'examples/utest/testcases/Kconfig 换成本 PR 中 Kconfig 里的 "components/utilities/utest/Kconfig" 即可。
dist的工程我觉得保留utest是没有影响的,对我来说是希望存在的,唯一来说目前可以看得到的影响就是需要在链接段加入utest的代码段,这个感觉影响不大

我原来是放在 components/utilities/utest/Kconfig 下的,但是后来改成了 Kconfig.utestcases 是有原因的,陈述如下:

每个模块的 Kconfig 应该负责本模块的配置定义,所以 components/utilities/utest/Kconfig 的意思应该是 utest 这个模块(注意 utest 不是 unit testcase,是一个用于 unit test 的 framework 软件模块)的配置选项。而我们现在需要的是一个定义哪些模块的 unit testcases 需要加入 RT-thread 的主菜单这么一件事情,所以用 components/utilities/utest/Kconfig 是不合适的。

所以我们现在实际上是需要定义一个 RTT 全局的单元测试集合的条目表,这是一个非常 high level 的 Kconfig,所以我觉得放在 RTT 的根目录下其实并不过分,原来我曾经考虑在 RTT 根目录下建一个目录 utestcases 下面放一个 Kconfig 文件,即 utestcases/Kconfig 但觉得多此一举,因为这个 utestcases 目录下其实不会有其他文件了。所以我定义了一个 Kconfig.utestcases 文件。我不清楚 RTT 的规范是什么,其实 kconfig 框架下只要有一个总入口 Kconfig 就可以了,其他 sourse 进来的文件并不一定也得叫 KCofnig 吧?

另外你说的 bsp_update_kconfig_testcases和exclude_utestcases可以删掉或者给注释掉 这个怕是不行,原因我在上面分析过了,对于 dist 来说,它在打包过程中会删掉 examples 这个目录,所以原来 dist 过程中需要通过移除 Kconfig 中的 rsource "examples/utest/testcases/Kconfig" 这一行。而现在同样要移除 Kconfig 中的 rsource Kconfig.utestcases 这一行,因为 Kconfig,utestcases 文件中会 rsource "examples/utest/testcases/utest/Kconfig" 等, examples 目录被 dist 删除后同样会导致这里失败。我的计划是目前保留 bsp_update_kconfig_testcasesexclude_utestcases 这个函数,只是把这个函数中删除 rsource "examples/utest/testcases/Kconfig" 这一行改成删除 rsource Kconfig.utestcases 这一行。等以后我们把 example 目录下所有的测试用例代码都移到其他目录下后,这时候才可以彻底地删除 bsp_update_kconfig_testcasesexclude_utestcases 这个函数以及调用他们的地方。

我的意思是这样:由于后续utest采用分布式策略,对应的测试用例都是归属在内核、组件目录下,而example本身是并没有构建系统的(scons脚本),在执行构建时并不会将其加入其中,那么原本在example下的utest彻底剥离出去后,其实也只有一个utest相关的Kconfig文件是需要的,那么这部分可以直接统一放在根目录下的Kconfig里是不是会好些,当然这部分前提是需要将example下的utest全部都剥离完,那么上述工作都做完之后,bsp_update_kconfig_testcasesexclude_utestcases 这两个函数是不是就不需要了,上述仅为我个人观点啊

@kurisaW
Copy link
Member

kurisaW commented Aug 26, 2025

跟汪老师讨论过了,先按照汪老师这种想法去推进,由汪老师来负责主导这部分工作,一点点推进utest分布式,那最终的一个效果就是会剔除掉example下所有的utest相关项,以及bsp_update_kconfig_testcasesexclude_utestcases 这两个函数;

同时默认显示的效果就是menuconfig下在一级目录下显示utest相关配置项,并且对应二级、三级...

我这边没啥问题了

@kurisaW
Copy link
Member

kurisaW commented Aug 26, 2025

LGTM

@Rbb666 Rbb666 merged commit 0fdeb4c into RT-Thread:master Aug 26, 2025
71 of 72 checks passed
@unicornx unicornx deleted the dev-utest-framework branch August 26, 2025 02:40
unicornx added a commit to unicornx/rt-thread that referenced this pull request Aug 26, 2025
After "utest: re-org utest framework (initial version)" (PR RT-Thread#10534)
was merged, adding a document to introduce how to add utest-cases
for your module.

Signed-off-by: Chen Wang <[email protected]>
Rbb666 pushed a commit that referenced this pull request Aug 26, 2025
After "utest: re-org utest framework (initial version)" (PR #10534)
was merged, adding a document to introduce how to add utest-cases
for your module.

Signed-off-by: Chen Wang <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants