Kenel Model 测试node
本内核模块测试主要是由三个子系统组成:用户态测试,内核态测试和接口测试。内核态测试经过编写内核模块代码,直接对avl原文件进行测试,能够执行全部的指令。出于运行安全的考虑,用户态的进程没法直接访问硬件和内核的内存空间,而是经过字符设备(ioctl)进入内核态调用,用户态测试时能够看到内核态经过printk函数的输出。接口测试用于检测内核态与用户态之间的交互点,重点是要检查数据的交换,传递和控制管理过程,以及相互逻辑依赖关系等。整体结构以下:安全
avl的测试包括下图几个方面,以add为例,具体说明avl函数接口测试的实现。框架
1、 内核态函数
Module中首先须要建立的文件有:avlat-test.h,avlat-add.c,Makefile.in 。其中avlat-test.h是包含全部测试的头文件(仿造spl内核模块编写便可),avlat-add.c是测试文件,Makefile.in是辅助编译生成文件(4.2中已提到)。测试
增长结点有三种状况:增长单个结点,增长多个结点,增长已存在结点。对应于这三种状况,能够设计三个测试用例。ui
1.增长单个结点spa
static int avlat_add_test_1(struct file *file, void *arg) { avl_tree_t *avl_test_tree; avlat_t *avlat_node, *first_node, *last_node; uint32_t avl_value=5, rc = 0; // step1: initial avl
avl_test_tree = kmalloc(sizeof(*avl_test_tree), GFP_KERNEL); avl_create(avl_test_tree, avl_test_compare, sizeof (avlat_t), offsetof(avlat_t, avl_node)); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_1-1.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step2: add sigle avl node and check avl_numnodes
avlat_node = kmalloc(sizeof(*avlat_node), GFP_KERNEL); avlat_node->avl_key=avl_value; avl_add(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 1) { printk("Error: avlat_add_test_1-2.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step3: check avl_first & avl_last
first_node = avl_first(avl_test_tree); last_node = avl_last(avl_test_tree); if ((first_node->avl_key != last_node->avl_key) || (first_node->avl_key != avl_value)) { printk("Error: avlat_add_test_1-3.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step4: remove avl node
avl_remove(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_1-4.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } kfree(avlat_node); // step5: destroy avl node
avl_destroy(avl_test_tree); kfree(avl_test_tree); return rc; }
2.增长多个结点设计
增长结点的测试用例为{10, 99, 178, 106, 7, 4, 44, 55, 1765, 200},以下图:3d
代码:code
static int avlat_add_test_2(struct file *file, void *arg) { avl_tree_t *avl_test_tree; avlat_t *avlat_node[10], *first_node, *last_node; uint32_t key_value[10]={10, 99, 178, 106, 7, 4, 44, 55, 1765, 200}; uint32_t i, num=10, rc=0; // step1: initial avl
avl_test_tree = kmalloc(sizeof(*avl_test_tree), GFP_KERNEL); avl_create(avl_test_tree, avl_test_compare, sizeof (avlat_t), offsetof(avlat_t, avl_node)); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_2-1.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step2: add multiple avl node and check avl_numnodes
for (i=0; i<num; i++) { avlat_node[i] = kmalloc(sizeof(*avlat_node[i]), GFP_KERNEL); avlat_node[i]->avl_key=key_value[i]; avl_add(avl_test_tree, avlat_node[i]); } if (avl_numnodes(avl_test_tree) != num) { printk("Error: avlat_add_test_2-2.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step3: check avl_first
first_node = avl_first(avl_test_tree); if (first_node->avl_key != 4) { printk("Error: avlat_add_test_2-3.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step4: check avl_last
last_node = avl_last(avl_test_tree); if (last_node->avl_key != 1765) { printk("Error: avlat_add_test_2-4.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step5: remove first avl node
avl_remove(avl_test_tree, avlat_node[1]); if (avl_numnodes(avl_test_tree) != (num-1)) { printk("Error: avlat_add_test_2-5.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } kfree(avlat_node[1]); // step6: check avl_first
first_node = avl_first(avl_test_tree); if (first_node->avl_key != 4) { printk("Error: avlat_add_test_2-6.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step7: check avl_last
last_node = avl_last(avl_test_tree); if (last_node->avl_key != 1765) { printk("Error: avlat_add_test_2-7.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step8: remove all avl nodes
for (i=0; i<num; i++) { if (i==1) { continue; } avl_remove(avl_test_tree, avlat_node[i]); kfree(avlat_node[i]); } if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_2-8.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step9: destroy avl node
avl_destroy(avl_test_tree); kfree(avl_test_tree); return rc; }
3.增长已存在结点
增长已存在的结点的,会报错。
代码:
static int avlat_add_test_3(struct file *file, void *arg) { avl_tree_t *avl_test_tree; avlat_t *avlat_node, *first_node, *last_node; uint32_t avl_value=12, rc=0; // step1: initial avl
avl_test_tree = kmalloc(sizeof(*avl_test_tree), GFP_KERNEL); avl_create(avl_test_tree, avl_test_compare, sizeof (avlat_t), offsetof(avlat_t, avl_node)); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_2-1.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step2: add sigle avl node and check avl_numnodes
avlat_node = kmalloc(sizeof(*avlat_node), GFP_KERNEL); avlat_node->avl_key=avl_value; avl_add(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 1) { printk("Error: avlat_add_test_3-2.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } /*// step3: add exists avl node and check avl_numnodes avl_add(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 1) { printk("Error: avlat_add_test_3-3.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; }*/ // step4: check avl_first & avl_last
first_node = avl_first(avl_test_tree); last_node = avl_last(avl_test_tree); if ((first_node->avl_key != last_node->avl_key) || (first_node->avl_key != avl_value)) { printk("Error: avlat_add_test_3-4.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step5: remove avl node
avl_remove(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_3-5.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } kfree(avlat_node); // step6: destroy avl node
avl_destroy(avl_test_tree); kfree(avl_test_tree); return rc; }
2、用户态
在cmd文件夹中的avlat文件夹中建立avlat.h和avlat.c,搭建用户态框架。能够直接经过虚拟机执行指令,主要指令用法以下:
3、用户态和内核态的通讯
用户态和内核态的通讯经过ioctl来实现,用户态经过ioctl接口设备进入内核态调用。在module文件夹中新建文件avlat-ctl.c,并在include中创建头文件avlat-ctl.h,来具体实现ioctl接口通讯。
申请设备:
ioctl接口在内核态的主要实现关键代码:
static long avlat_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rc = 0; /* Ignore tty ioctls */ if ((cmd & 0xffffff00) == ((int)'T') << 8) return -ENOTTY; switch (cmd) { case AVLAT_CFG: rc = avlat_ioctl_cfg(file, cmd, arg); break; case AVLAT_CMD: rc = avlat_ioctl_cmd(file, cmd, arg); break; default: avlat_print(file, "Bad ioctl command %d\n", cmd); rc = -EINVAL; break; } return rc; }
ioctl接口在用户态的调用:
用户态进入内核态调用运行结果:
标注:此篇仅用以说明内核模块测试的用户态和内核态的交互经过代码具体实现的思路,不包含具体代码及代码指导。