LTP 第一章 LTP介绍及内部机制

来源:互联网 发布:大数据新闻标题 编辑:程序博客网 时间:2024/06/07 22:24

LTP系列链接:

本文同步发布于我的个人网站:LTP教程

第一章 LTP介绍及内部机制

第二章 开发Shell测试集

第三章 开发系统调用测试集

第四章 开发_exit()测试集

第五章 开发IO操作测试集

第六章 开发IO阻塞测试集


1 LTP介绍及内部机制

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

首先执行下面命令安装相关软件包(已安装可跳过):

#CentOSsudo yum install autoconf  automake  autotools-dev m4#Ubuntusudo apt-get install autoconf  automake  autotools-dev m4

在上节中我将ltp项目下载到了wxs用户的家目录(/home/wxs)下,如图所示:

[wxs@bogon ~]$ cd ltp/[wxs@bogon ltp]$ lsaclocal.m4      configure.ac  INSTALL           pan                   testcasesautom4te.cache  confLkNw6U    install-sh        README.kernel_config  testscriptsconfc20wzw      COPYING       lib               README.md             TODOconfig.guess    doc           ltpmenu           runltp                toolsconfig.log      execltp       m4                runltplite.sh         utilsconfig.status   execltp.in    Makefile          runtest               ver_linuxconfig.sub      IDcheck.sh    Makefile.release  scenario_groups       Versionconfigure       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]$ lsbin         runltp         runtest          share      testscripts  VersionIDcheck.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]$ lscommands  demoA  kernel  Makefile  network               realtimecve       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_udpcan                 kernel_misc            net_stress.multicastcap_bounds          ltp-aiodio.part1       net_stress.routecommands            ltp-aiodio.part2       net.tcp_cmdsconnectors          ltp-aiodio.part3       net.tirpc_testscontainers          ltp-aiodio.part4       network_commandscontrollers         ltp-aio-stress.part1   nptlcpuhotplug          ltp-aio-stress.part2   numacrashme             ltplite                pipescve                 lvm.part1              power_management_testsdio                 lvm.part2              power_management_tests_exclusivedma_thread_diotest  math                   ptyfcntl-locktests     mm                     quickhitfilecaps            modules                schedfs                  net.features           scsi_debug.part1fs_bind             net.ipv6               securebitsfs_ext4             net.ipv6_lib           smackfs_perms_simple     net.multicast          stress.part1fs_readonly         net.nfs                stress.part2fsx                 net.rpc                stress.part3hugetlb             net.rpc_tests          syscallshyperthreading      net.sctp               syscalls-ipcima                 net_stress.appl        timersinput               net_stress.broken_ip   tpm_toolsio                  net_stress.interface   tracingio_cd               net_stress.ipsec_icmpio_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.mkinclude $(top_srcdir)/include/mk/generic_leaf_target.mksqrt:  LDLIBS += -lm

需要注意的是,这里的top_srcdir指的是ltp目录,因为demoA目录位于ltp目录的内两层,所以使用了../..

还需要注意的是,要想成功使用sqrt命令必须附加-lm参数,在Makefile中已经体现这一点。

执行make命令,生成可执行文件sqrt

[wxs@bogon demoA]$ makemake -C "/home/wxs/ltp/lib" -f "/home/wxs/ltp/lib/Makefile" allmake[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 sqrtsqrt.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=1506106767cmdline="sqrt"contacts=""analysis=exit<<<test_output>>>tst_test.c:915: INFO: Timeout per run is 0h 05m 00sincrementing stopsqrt.c:20: FAIL: sqrt() failedsqrt.c:23: PASS: sqrt() succeedsSummary:passed   1failed   1skipped  0warnings 0<<<execution_status>>>initiation_status="ok"duration=0 termination_type=exited termination_id=1 corefile=nocutime=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.shecho_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 sqrtecho 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 00ssqrt.c:20: FAIL: sqrt() failedsqrt.c:23: PASS: sqrt() succeedsSummary:passed   1failed   1skipped  0warnings 0<<<execution_status>>>initiation_status="ok"duration=1 termination_type=exited termination_id=1 corefile=nocutime=0 cstime=0<<<test_end>>><<<test_start>>>tag=echo stime=1506107663cmdline="echo.sh"contacts=""analysis=exit<<<test_output>>>incrementing stop 1 TPASS:  sucessedSummary:passed   1failed   0skipped  0warnings 0<<<execution_status>>>initiation_status="ok"duration=0 termination_type=exited termination_id=0 corefile=nocutime=2 cstime=5<<<test_end>>>···

本次测试输出包含两个test体,第一个test体我们在上一节已经说过了,我们直接看第二个test体。该体中共计有1个测试点,状态为TPASS。

对照echo.sh中的测试点,发现没有问题。

至此你已经学会了最基本的创建C和Shell的测试用例以及整体测试的方法,本章内容你已经完成了。


原创粉丝点击