赞
踩
https://blog.csdn.net/yuanlaijike/article/details/78068331
1.1 LTP介绍
1.1.1 功能测试
1.1.2 回归测试
1.1.3 压力测试
1.2 LTP环境部署
1.2.1 下载LTP
1.2.2 部署LTP
1.3 目录结构
1.3.1 源码包
1.3.2 安装包
1.4 测试框架
1.4.1 整体测试流程
1.4.2 测试用例执行流程
1.4.3 测试库
1.5 测试执行
1.5.1 整体测试
1.5.2 单独测试
1.5.2.1 安装包测试
1.5.2.2 源码包测试
1.6 牛刀小试
1.6.1 验证sqrt() 函数
1.6.2 验证echo命令
源码地址:https://github.com/jitwxs/blog_sample
1.1 LTP介绍
LTP(Linux Test Project),是基于GPL协议的开源社区合作项目。2000年由SGI发起,IBM、OSDL和Bull等公司共同参与,2001年后由SUSE、富士通、Red Hat、Oracle共同开发和维护。
通过功能测试、压力测试和回归测试来验证Linux系统的可靠性、稳定性和健壮性。整个项目约4000个测试用例,绝大部分用例采用C或Shell。
LTP不仅测试内核,还测试整体系统环境,对功能执行失败时的返回和处理也进行测试。
1.1.1 功能测试
主要对man pages中1、8命令和2系统调用所描述的功能进行验证。
1.1.2 回归测试
修改了旧代码后,重新进行测试已确认修改没有引入新的错误或导致其他代码产生错误。
1.1.3 压力测试
测试系统功能特性再大负荷压力下的稳定性和可靠性。
1.2 LTP环境部署
1.2.1 下载LTP
LTP项目目前位于GitHub,项目地址:https://github.com/linux-test-project/ltp
获取最新版可以执行以下命令:git clone https://github.com/linux-test-project/ltp.git
1.2.2 部署LTP
首先执行下面命令安装相关软件包(已安装可跳过):
- #CentOS
- sudo yum install autoconf automake autotools-dev m4
-
- #Ubuntu
- sudo apt-get install autoconf automake autotools-dev m4
在上节中我将ltp项目下载到了wxs用户的家目录(/home/wxs)下,如图所示:
- [wxs@bogon ~]$ cd ltp/
- [wxs@bogon ltp]$ ls
- aclocal.m4 configure.ac INSTALL pan testcases
- autom4te.cache confLkNw6U install-sh README.kernel_config testscripts
- confc20wzw COPYING lib README.md TODO
- config.guess doc ltpmenu runltp tools
- config.log execltp m4 runltplite.sh utils
- config.status execltp.in Makefile runtest ver_linux
- config.sub IDcheck.sh Makefile.release scenario_groups Version
- configure include missing scripts VERSION
进入ltp目录:cd ltp
生成自动工具:make autotools
系统环境配置:./configure
编译:make -j$(getconf_NPROCESSORS_ONLN)
安装:sudo make install
依次执行以上命令后,LTP已经被正确安装到你的Linux系统中,默认安装位于/opt/ltp/。
- [wxs@bogon ltp]$ cd /opt/ltp/
- [wxs@bogon ltp]$ ls
- bin runltp runtest share testscripts Version
- IDcheck.sh runltplite.sh scenario_groups testcases ver_linux
需要注意的是,我们通过git clone命令下载的位于home目录下的ltp文件夹为ltp源码文件夹,我将在后文简称为源码包。
通过执行一系列命令安装到/opt目录下的ltp文件夹为ltp安装文件夹,我将在后文简称为安装包。
1.3 目录结构
1.3.1 源码包
LTP源码包目录结构描述如下:
名称 说明
INSTALL LTP安装配置指导文档
README LTP介绍
CREDITS 记录对LTP有很大贡献的人
COPYING GNU公开许可证
ChangeLog 描述版本变化
ltpmenu 规划执行LTP的图形化界面接口
Makefile LTP顶层目录的Makefile,负责编译安装pan、testcases和tools
runalltests.sh 顺序运行全部测试用例并且报告结果的脚本
doc/* 工程文档包含工具和库函数使用手册,描述各种测试
include/* 通用的头文件目录
lib/* 通用的函数目录
testcases/* 包含在LTP下运行和bin目录下的所有测试用例和链接
testscripts/* 存放分组的测试脚本
runtest/* 为自动化测试提供命令列表
pan/* 测试的驱动装置,具备随机和并行测试的能力
scratch/* 存放零碎测试
tools/* 存放自动化测试脚本和辅助工具
LTP测试套件包含以下内容:
- [wxs@bogon ~]$ cd ltp/testcases/
- [wxs@bogon testcases]$ ls
- commands demoA kernel Makefile network realtime
- cve kdump lib misc open_posix_testsuite
目录结构描述如下:
名称 说明
commands 常用命令测试
kernel 内核模块及其相关模块
kdump 内核现崩溃转储测试
network 网络测试
realtime 系统实时性测试
open_posix_testsuite posix标准测试
misc 崩溃、核心转出、浮点运算等测试
1.3.2 安装包
LTP安装包目录结构描述如下:
名称 说明
bin 存放LTP测试的一些辅助脚本
results 测试结果默认存储目录
testcases 测试项集
output 测试日志默认存储目录
share 脚本使用说明目录
runtest 测试驱动(用于链接testscripts内的测试脚本和testcases测试项目)
lib 通用的库函数目录
1.4 测试框架
1.4.1 整体测试流程
ltp安装包根目录下的runltp脚本是LTP自动测试系统的入口,其提供了一系列参数选项,允许用户设定测试环境制定测试集、控制测试结果输出方式和路径等,运行runltp会生成指定的测试列表并调用测试驱动PAN来开始测试,待执行完毕后根据PAN返回的结果来生成报告。
PAN是LTP的一组测试驱动程序,负责实际测试的执行,根据runltp传递的参数和测试列表来依次执行测试,输出执行过程中的详细信息,对每个测试用例的执行结果进行统计,并将整体测试结果返回给runltp。
整体测试流程
1.4.2 测试用例执行流程
测试用例执行流程
测试结果的输出类型如下:
Type Description
BROK 程序执行中途发生错误而使测试遭到破坏
CONF 测试环境不满足而跳过执行
WARN 测试中途发生异常
INFO 输出通用测试信息
PASS 测试成功
FAIL 测试失败
1.4.3 测试库
LTP目前测试库存在新旧测试库交替的情况,本文均采用新测试库的框架,具体的更新说明可以参考更新文档An update on the Linux Test Project。
测试库
Old Library New Library
测试用例在执行时调用测试库的API 在测试库维护的子进程中回调测试用例
setup()中逐一调用API完成测试准备 setup()中测试属性以结构体变量定义
main()定义在每个测试用例当中 main()定义在测试库中
cleanup()中不能调用SAFE函数 cleanup()中允许调用SAFE函数
这里以umount02为例,比较新旧框架的区别:
旧框架代码:
- //Example using the old LTP library
- //https://lwn.net/Articles/708250/
-
- #include <errno.h>
- #include <sys/mount.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/fcntl.h>
- #include <pwd.h>
-
- #include "test.h"
- #include "safe_macros.h"
-
- static void setup(void);
- static void cleanup(void);
-
- char *TCID = "umount02";
- #define DIR_MODE S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH
- #define FILE_MODE S_IRWXU | S_IRWXG | S_IRWXO
- #define MNTPOINT "mntpoint"
-
- static char long_path[PATH_MAX + 2];
- static int mount_flag;
- static int fd;
-
- static const char *device;
-
- static struct test_case_t {
- char *err_desc;
- char *mntpoint;
- int exp_errno;
- char *exp_retval;
- } testcases[] = {
- {"Already mounted/busy", MNTPOINT, EBUSY, "EBUSY"},
- {"Invalid address space", NULL, EFAULT, "EFAULT"},
- {"Directory not found", "nonexistent", ENOENT, "ENOENT"},
- {"Invalid device", "./", EINVAL, "EINVAL"},
- {"Pathname too long", long_path, ENAMETOOLONG, "ENAMETOOLONG"}
- };
-
- int TST_TOTAL = ARRAY_SIZE(testcases);
-
- int main(int ac, char **av)
- {
- int lc, i;
-
- tst_parse_opts(ac, av, NULL, NULL);
-
- setup();
-
- for (lc = 0; TEST_LOOPING(lc); lc++) {
- tst_count = 0;
-
- for (i = 0; i < TST_TOTAL; ++i) {
- TEST(umount(testcases[i].mntpoint));
-
- if ((TEST_RETURN == -1) && (TEST_ERRNO == testcases[i].exp_errno)) {
- tst_resm(TPASS, "umount(2) expected failure; "
- "Got errno - %s : %s",
- testcases[i].exp_retval,
- testcases[i].err_desc);
- } else {
- tst_resm(TFAIL, "umount(2) failed to produce "
- "expected error; %d, errno:%s got %d",
- testcases[i].exp_errno,
- testcases[i].exp_retval, TEST_ERRNO);
- }
- }
- }
-
- cleanup();
- tst_exit();
- }
-
- static void setup(void)
- {
- const char *fs_type;
-
- tst_sig(FORK, DEF_HANDLER, cleanup);
-
- tst_require_root();
-
- tst_tmpdir();
-
- fs_type = tst_dev_fs_type();
- device = tst_acquire_device(cleanup);
-
- if (!device)
- tst_brkm(TCONF, cleanup, "Failed to obtain block device");
-
- tst_mkfs(cleanup, device, fs_type, NULL, NULL);
-
- memset(long_path, 'a', PATH_MAX + 1);
-
- SAFE_MKDIR(cleanup, MNTPOINT, DIR_MODE);
-
- if (mount(device, MNTPOINT, fs_type, 0, NULL))
- tst_brkm(TBROK | TERRNO, cleanup, "mount() failed");
-
- mount_flag = 1;
-
- fd = SAFE_OPEN(cleanup, MNTPOINT "/file", O_CREAT | O_RDWR);
-
- TEST_PAUSE;
- }
-
- static void cleanup(void)
- {
- if (fd > 0 && close(fd))
- tst_resm(TWARN | TERRNO, "Failed to close file");
-
- if (mount_flag && tst_umount(MNTPOINT))
- tst_resm(TWARN | TERRNO, "umount() failed");
-
- if (device)
- tst_release_device(device);
-
- tst_rmdir();
- }
新框架代码:
- //Example using the new LTP library
- //https://lwn.net/Articles/708251/
-
- #include <errno.h>
- #include <string.h>
- #include <sys/mount.h>
- #include "tst_test.h"
-
- #define MNTPOINT "mntpoint"
-
- static char long_path[PATH_MAX + 2];
- static int mount_flag;
- static int fd;
-
- static struct tcase {
- const char *err_desc;
- const char *mntpoint;
- int exp_errno;
- } tcases[] = {
- {"Already mounted/busy", MNTPOINT, EBUSY},
- {"Invalid address", NULL, EFAULT},
- {"Directory not found", "nonexistent", ENOENT},
- {"Invalid device", "./", EINVAL},
- {"Pathname too long", long_path, ENAMETOOLONG}
- };
-
- static void verify_umount(unsigned int n)
- {
- struct tcase *tc = &tcases[n];
-
- TEST(umount(tc->mntpoint));
-
- if (TEST_RETURN != -1) {
- tst_res(TFAIL, "umount() succeeds unexpectedly");
- return;
- }
-
- if (tc->exp_errno != TEST_ERRNO) {
- tst_res(TFAIL | TTERRNO, "umount() should fail with %s",
- tst_strerrno(tc->exp_errno));
- return;
- }
-
- tst_res(TPASS | TTERRNO, "umount() fails as expected: %s",
- tc->err_desc);
- }
-
- static void setup(void)
- {
- memset(long_path, 'a', PATH_MAX + 1);
-
- SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL);
- SAFE_MKDIR(MNTPOINT, 0775);
- SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL);
- mount_flag = 1;
-
- fd = SAFE_CREAT(MNTPOINT "/file", 0777);
- }
-
- static void cleanup(void)
- {
- if (fd > 0 && close(fd))
- tst_res(TWARN | TERRNO, "Failed to close file");
-
- if (mount_flag)
- tst_umount(MNTPOINT);
- }
-
- static struct tst_test test = {
- .tid = "umount02",
- .tcnt = ARRAY_SIZE(tcases),
- .needs_root = 1,
- .needs_tmpdir = 1,
- .needs_device = 1,
- .setup = setup,
- .cleanup = cleanup,
- .test = verify_umount,
- };
1.5 测试执行
1.5.1 整体测试
我们可以测试所有的测试集,直接运行runltp命令将测试ltp/scenario_groups/default中的所有测试集,一次测试约2~3小时。
- [wxs@bogon ltp]$ cd /opt/ltp
- [wxs@bogon ltp]$ sudo ./runltp
当然我们可以只测试某个测试集,测试集可以在ltp/runtest/下查看。
- [wxs@bogon ltp]$ ls runtest/
- admin_tools ipc net_stress.ipsec_udp
- can kernel_misc net_stress.multicast
- cap_bounds ltp-aiodio.part1 net_stress.route
- commands ltp-aiodio.part2 net.tcp_cmds
- connectors ltp-aiodio.part3 net.tirpc_tests
- containers ltp-aiodio.part4 network_commands
- controllers ltp-aio-stress.part1 nptl
- cpuhotplug ltp-aio-stress.part2 numa
- crashme ltplite pipes
- cve lvm.part1 power_management_tests
- dio lvm.part2 power_management_tests_exclusive
- dma_thread_diotest math pty
- fcntl-locktests mm quickhit
- filecaps modules sched
- fs net.features scsi_debug.part1
- fs_bind net.ipv6 securebits
- fs_ext4 net.ipv6_lib smack
- fs_perms_simple net.multicast stress.part1
- fs_readonly net.nfs stress.part2
- fsx net.rpc stress.part3
- hugetlb net.rpc_tests syscalls
- hyperthreading net.sctp syscalls-ipc
- ima net_stress.appl timers
- input net_stress.broken_ip tpm_tools
- io net_stress.interface tracing
- io_cd net_stress.ipsec_icmp
- io_floppy net_stress.ipsec_tcp
- [wxs@bogon ltp]$ sudo ./runltp -f modules
需要注意的是,如果我们测试某个测试集,runltp需要指定-f参数。
1.5.2 单独测试
如果我们不想测试某个测试集,只想测试某个单独的测试,可以采用安装包测试或者源码包测试。下面以access01为例,讲解单独测试。
1.5.2.1 安装包测试
进入安装包,执行以下命令即可。
- [wxs@bogon ltp]$ cd /opt/ltp/
- [wxs@bogon ltp]$ sudo ./runltp -s access01
需要注意的是,如果我们测试某个测试,runltp需要指定-s参数。
1.5.2.2 源码包测试
进入源码包,找到access01的位置,直接执行./access01即可。
- [wxs@bogon access]$ cd ~/ltp/testcases/kernel/syscalls/access/
- [wxs@bogon access]$ sudo ./access01
我们看到access01位于testcases目录下,实际上testcases目录下每个文件都是一个完整的可执行程序,可以在编译后的源码路径直接执行。
1.6 牛刀小试
本节中牵扯到的项目均位于源码包testcases下自建的demoA文件夹中。测试方法均采用测试集测试(C实现的测试用例可以采用源码测试和测试集测试,Shell实现的测试用例只可以采用测试集测试)。
- [wxs@bogon ~]$ cd ~/ltp/testcases/
- [wxs@bogon testcases]$ mkdir demoA
- [wxs@bogon testcases]$ cd demoA/
- [wxs@bogon demoA]$ pwd
- /home/wxs/ltp/testcases/demoA
1.6.1 验证sqrt() 函数
参考1.3.3节中给出的示例代码,编写测试用例sqrt.c:
- #include <errno.h>
- #include <string.h>
- #include <sys/mount.h>
- #include "tst_test.h"
-
- static struct tcase {
- const int input;
- const int output;
- } tcases[] = {
- {-1,1},
- {9,3}
- };
-
- static void testSqrt(unsigned int n){
- struct tcase *tc = &tcases[n];
-
- TEST(sqrt(tc->input));
-
- if (TEST_RETURN != tc->output) {
- tst_res(TFAIL, "sqrt() failed");
- return;
- }
- tst_res(TPASS, "sqrt() succeeds");
- }
-
- static struct tst_test test = {
- .tid = "testSqrt",
- .tcnt = ARRAY_SIZE(tcases),
- .test = testSqrt,
- };
参考testcases目录下的其他Makefile文件,编写Makefile:
- top_srcdir ?= ../..
-
- include $(top_srcdir)/include/mk/testcases.mk
-
- include $(top_srcdir)/include/mk/generic_leaf_target.mk
-
- sqrt: LDLIBS += -lm
需要注意的是,这里的top_srcdir指的是ltp目录,因为demoA目录位于ltp目录的内两层,所以使用了../..。
还需要注意的是,要想成功使用sqrt命令必须附加-lm参数,在Makefile中已经体现这一点。
执行make命令,生成可执行文件sqrt:
[wxs@bogon demoA]$ make
make -C "/home/wxs/ltp/lib" -f "/home/wxs/ltp/lib/Makefile" all
make[1]: 进入目录“/home/wxs/ltp/lib”
make[2]: 进入目录“/home/wxs/ltp/lib/newlib_tests”
make[2]: 对“all”无需做任何事。
make[2]: 离开目录“/home/wxs/ltp/lib/newlib_tests”
make[2]: 进入目录“/home/wxs/ltp/lib/tests”
make[2]: 对“all”无需做任何事。
make[2]: 离开目录“/home/wxs/ltp/lib/tests”
make[1]: 离开目录“/home/wxs/ltp/lib”
gcc -g -O2 -g -O2 -fno-strict-aliasing -pipe -Wall -W -Wold-style-definition -D_FORTIFY_SOURCE=2 -I../../include -I../../include -I../../include/old/ -L../../lib sqrt.c -lltp -lm -o sqrt
sqrt.c: 在函数‘testSqrt’中:
sqrt.c:17:2: 警告:隐式声明函数‘sqrt’ [-Wimplicit-function-declaration]
TEST(sqrt(tc->input));
^
In file included from sqrt.c:4:0:
sqrt.c:17:7: 警告:隐式声明与内建函数‘sqrt’不兼容 [默认启用]
TEST(sqrt(tc->input));
^
../../include/tst_test.h:176:17: 附注:in definition of macro ‘TEST’
TEST_RETURN = SCALL; \
^
这里可以直接执行命令./sqrt来运行这个测试用例,但是对于下节的shell测试用例就不能这样做了,本节我都将它写在自定义测试集中。
首先复制可执行文件sqrt到安装包的testcases/bin/目录下:
[wxs@bogon demoA]$ sudo cp sqrt /opt/ltp/testcases/bin/
然后进入安装包的runtest目录下,编写自定义测试用例集demoA:
- [wxs@bogon runtest]$ cat demoA
- sqrt sqrt
-
测试用例集中每个测试用例包括两部分:前部分为昵称,后部分为testcases/bin/目录下的文件名,中间用空格分隔。
进入上层目录,执行整体测试命令:
- [wxs@bogon runtest]$ cd ..
- [wxs@bogon ltp]$ sudo ./runltp -f demoA
执行后程序会输出一大段,我们只需关心最重要的部分。我定义从<<<test_start>>>到<<<test_end>>>中间的内容为test体,后文均以此称呼:···
- <<<test_start>>>
- tag=sqrt stime=1506106767
- cmdline="sqrt"
- contacts=""
- analysis=exit
- <<<test_output>>>
- tst_test.c:915: INFO: Timeout per run is 0h 05m 00s
- incrementing stop
- sqrt.c:20: FAIL: sqrt() failed
- sqrt.c:23: PASS: sqrt() succeeds
-
- Summary:
- passed 1
- failed 1
- skipped 0
- warnings 0
- <<<execution_status>>>
- initiation_status="ok"
- duration=0 termination_type=exited termination_id=1 corefile=no
- cutime=0 cstime=0
- <<<test_end>>>
可以看到,两个测试点一个FAIL,一个PASS。对照sqrt.c文件中给出的测试数据,发现测试没有问题。至此,一个简单的LTP测试用例就完成了。
1.6.2 验证echo命令
重新回到demoA文件夹中,编写echo.sh文件,代码可以参考源码包中testcases/commands中其他的测试用例:#测试函数执行次数
TST_CNT=1
#测试用例启动函数
- TST_TESTFUNC=do_test
- . tst_test.sh
-
- echo_test()
- {
- local std_in=$1
- local echo_cmd=$(echo $std_in > a.out)
- local echo_res=$std_in
- local cat_res=$(cat a.out)
-
- if [ $echo_res = $cat_res ]
- then
- tst_res TPASS "$echo_cmd sucessed"
- else
- tst_res TFAIL "$echo_cmd failed"
- fi
- }
-
- do_test()
- {
- echo_test "hello\tworld"
- }
-
- tst_run
为echo.sh添加可执行权限,并复制到安装包中的testcases/bin/目录中。
这里一定要注意,不可以在当前路径直接./echo.sh执行测试用例!!
- [wxs@bogon demoA]$ pwd
- /home/wxs/ltp/testcases/demoA
- [wxs@bogon demoA]$ sudo chmod +x echo.sh
- [wxs@bogon demoA]$ sudo cp echo.sh /opt/ltp/testcases/bin/
修改上一节中编写的demoA测试用例集,将echo.sh测试用例添加进去:
- [wxs@bogon demoA]$ cd /opt/ltp/runtest/
- [wxs@bogon runtest]$ cat demoA
- sqrt sqrt
- echo echo.sh
注意了,此时测试用例集中包含了两个测试用例,那么后面运行该测试用例集将会执行这两个测试用例。
进入上层目录,执行整体测试命令:
- [wxs@bogon runtest]$ cd ..
- [wxs@bogon ltp]$ sudo ./runltp -f demoA
结果输出依然很多,我们依然只看最关键的部分:
··· <<<test_output>>> tst_test.c:915: INFO: Timeout per run is 0h 05m 00s sqrt.c:20: FAIL: sqrt() failed sqrt.c:23: PASS: sqrt() succeeds Summary: passed 1 failed 1 skipped 0 warnings 0 <<<execution_status>>> initiation_status="ok" duration=1 termination_type=exited termination_id=1 corefile=no cutime=0 cstime=0 <<<test_end>>> <<<test_start>>> tag=echo stime=1506107663 cmdline="echo.sh" contacts="" analysis=exit <<<test_output>>> incrementing stop 1 TPASS: sucessed Summary: passed 1 failed 0 skipped 0 warnings 0 <<<execution_status>>> initiation_status="ok" duration=0 termination_type=exited termination_id=0 corefile=no cutime=2 cstime=5 <<<test_end>>> ···
本次测试输出包含两个test体,第一个test体我们在上一节已经说过了,我们直接看第二个test体。该体中共计有1个测试点,状态为TPASS。
对照echo.sh中的测试点,发现没有问题。
至此你已经学会了最基本的创建C和Shell的测试用例以及整体测试的方法,本章内容你已经完成了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。