网络设备自动化测试框架
          NATFNetsork automation test frame
   

第1章 概述

随着internet的发展,网络设备功能日渐复杂和多样,测试消耗的资源也越来越庞大,测试本身是无穷的,而智能化的人力资源却是有限的,所以如何将有限的人力精兵投入到复杂的测试中去而避免在细小的功能验证上耗费人力是每一个测试人员的理想。那么要做到这一点行之有效的方法就是细分测试种类,将简单的功能性测试由自动化完成,性能及复杂的组合、异常等等的测试有人力完成,这样一方面可以提高测试资源的利用率,一方面可以扩大测试的覆盖率。形成系统的测试闭环。
近年来,自动化测试被越来越多的重视并实践,当前主流网络设备厂商已经在自动化测试领域取得了很大的成绩,自动化测试覆盖率也逐渐在提高。而各个厂商自动化测试的平台是不同的,测试框架也就肯定是不同的,联想网御主要使用SecureCRT作为测试平台,SecureCRT本身提供了Jscript和VBscript两种脚本语言的支持。所以在SecureCRT的基础之上便诞生了NATF的框架。
网络设备自动化测试框架NATF(Network automation test frame)旨在设计出一种用命令行完成配置的网络设备(如防火墙、路由器、交换机等)的自动化功能性测试框架。整个框架可以分为如下几个部分:
测试床文件:该文件描述了实际物理设备的物理连接、组网及相关配置。
逻辑拓扑文件:因为在实际的测试过程中不同的模块的测试组网不尽相同,而为不同的模块来搭建不同的物理网络环境就显得耗时费力不实际,逻辑拓扑将测试组网跟实际组网环境脱离,多个逻辑拓扑文件共用一个测试床文件,在脚本执行过程中自动完成逻辑设备到物理设备的映射。这样做有两方面的好处:一方面只要完成了测试床环境的搭建,不许改变环境便可以完成多个模块的测试;另一方面为脚本的移植带来极大的方便,只需自行设计测试床而无需动用逻辑拓扑及具体的脚本文件。
测试脚本:原则上每一个测试用例可以用一个测试脚本来实现。而测试脚本的设计既要考虑到测试用例的粒度,既不能过于单一也不能过于繁琐,单一会造成不紧凑的感觉,繁琐又会给定位带来很大的不便。
测试集:同一模块的多个脚本及多个模块的测试集可以组成一个测试集文件。
整个测试框架实质上是一个分层的结构:
clip_p_w_picpath001
在测试的过程之中,测试的文件的解析是由下往上的,先解析测试床文件完成设备基本配置工作,然后解析逻辑拓扑文件完成逻辑设备到物理设备的映射(手动/自动),接着执行单个的测试脚本,最后等所有测试脚本完成之后便完成了测试集的解析执行。测试文件的执行恰好是由上往下的,以测试集文件作为入口文件开始执行,然后分别执行每个独立的脚本文件,在每个脚本文件执行的过程中会完成逻辑拓扑到测试床的映射进而正确的执行脚本。在执行脚本的过程中,每一步都会将执行结果记入日志文件,在测试集执行完毕之后系统会根据*.log的日志文件生成测试结果的*.exl文件并以邮件的方式发送到管理员邮箱中,以便管理员可以及时的看到测试结果并对FAIL项进行定位。
在脚本的执行过程中,一般会经过如下几个步骤:
1. 解析测试床文件,完成物理设备的接口地址及静态路由等的基本配置工作,保证物理组网环境正确畅通。
2. 解析测试集文件,按照顺序执行测试集中的测试脚本。
3. 在执行测试脚本之前解析逻辑拓扑文件并完成逻辑设备到物理设备的映射,映射包括逻辑设备到物理设备的映射,逻辑接口到物理接口的映射。完成映射之后通过读取逻辑设备接口信息可以得到实际的接口IP、掩码等。
4. 具体的测试脚本的执行。脚本执行一般有如下几个步骤:首先完成基本的配置,然后是每一步的功能检查,最后清除配置保证测试环境干净。

第2章 NATF的基本组成

2.1 测试床

测试床文件从某一种意义上是实际物理组网拓扑的文件描述。也就是说用文件的方
方式把物理环境进行了描述,进而形成了自动化测试框架中的测试床。测试床文件一般来说相对较复杂且具有典型性,因为它的设计要考虑到涵盖各个模块的组网环境,以求用最简最完备的环境完成环境描述。
而测试床文件的功能却又不仅限于此,测试床文件在完成物理拓扑描述的同时还必须肩负起基本网络配置功能,也就是说在在解析测试床文件的过程中呢必须识别环境中用到了那些设备、设备接口、接口的IP地址及基本路由等。并且在解析过程中自动完成接口IP地址的配置及基本路由的配置。这一部分是跟具体脚本无关的,因为脚本文件中所有的接口都采用了物理的而非实际的。
下面是一个举例的测试床文件(*.tbd),从中可以看出测试床文件的一些设计细节。
[TITLE]1.1.1 防火墙部分NAT模块测试床
[PHY-TOP]
"
F0/0 F0/1 F0/0
R1-------R2-------R3------R4
F0/0 F0/1 F0/0
"
[SESSION]
R1:Router1
R2:Router2
R3:Router3
[PHY-LINK]
R1 F0/0 1.1.1.1 255.255.255.0;R2 F0/0 1.1.1.2 255.255.255.0
R1 F0/1 2.1.1.1 255.255.255.0;R2 F0/1 2.1.1.2 255.255.255.0
R2 F1/0 3.1.1.1 255.255.0.0;R3 F1/0 3.1.1.2 255.255.0.0
R2 F2/0 4.1.1.1 255.255.0.0;R3 F2/0 4.1.1.2 255.255.0.0
[INIT]
R1:
ip route 3.1.1.0 255.255.255.0 1.1.1.2
ip route 4.1.1.0 255.255.255.0 2.1.1.2
R2:
R3:
ip route 1.1.1.0 255.255.255.0 3.1.1.1
ip route 2.1.1.0 255.255.255.0 4.1.1.1
[END]
说明: [TOPNAME]说明了该测试床文件的名称。
[LOGICTOP]描述了物理组网环境。
[SESSION]描述了具体的设备通过secureCRT连接的会话名称
[LINK]描述了具体的物理设备的连接情况及IP情况。
[INIT]描述了每个物理设备需要进行的基本配置。一般包括基本路由、默认防火墙规则等。
测试床文件为*.tbd文件,在执行脚本过程中首先会进行测试床文件的解析,在解析过程中对设备的接口IP、路由等进行配置。完成测试环境的初始化。

2.2 逻辑拓扑

逻辑拓扑是实际物理组网的一个抽象,因为每个模块功能是不同的,所以运用的环境也肯定是不同的,而在实际的测试过程中就不可能为每个模块都搞一套环境,所以将具体的测试环境抽象成为逻辑拓扑跟测试床独立,在测试的过程中进行逻辑到物理的映射,如此在进行脚本移植的过程中只需物理环境根据需要自行设计而逻辑拓扑及脚本则不发生变化,这样免去了很多的重复工作。
下面是一个逻辑拓扑的举例:
[TITLE] 1.1.1 防火墙部分NAT模块SNAT基本功能逻辑拓扑
[LOGIC TOP]
"
PORT1 PORT1
DUT1----------------DUT-------------DUT2
PORT2 PORT2
"
[LOGIC DEVICE]
DUT1 DUT DUT2
[LOGIC LINK]
DUT1 PORT1<--->DUT PORT1
DUT PORT3<--->DUT2 PORT1
[TOP END]
说明:[TITLE] 逻辑拓扑名称
[LOGIC TOP]逻辑拓扑组网。组网中设备名及端口名均为逻辑名。所有脚本
中涉及到的设备及接口名均为该逻辑名。
[LOGIC DEVICE]逻辑设备名,最后需要跟物理设备映射对应。最终获取到
具体物理设备的会话名。以便脚本中通过该会话在SecureCRT中访问到设备。
[LOGIC LINK]逻辑设备之间的连接关系。在逻辑拓扑映射的过程中逻辑连
接要跟物理设备连接进行映射关联,关联之后呢通过访问逻辑接口便可以
访问到物理接口,进一步可以获取物理接口ip地址等信息。

2.3 测试脚本

一般情况下,整个测试体系应当是一体的,在项目开发过程中开发人员需要提交相关的测试交付件,这些交付件一般会包括SRS,SOW,系统测试用例,缺陷文档等等。在项目验收测试过程中由测试人员完成测试点、测试用例的写作,然后以测试用例为蓝本进行测试脚本的写作,然后入库形成基线。测试脚本作为测试交付件,一个测试用例对应一个测试脚本或着多个测试脚本。
从测试的角度来看测试脚本可以这样来理解,测试脚本主要完成三个功能:配置下发、功能检查、结果输出。下面以一个具体的实例来介绍:
# $language = "JScript"
# $interface = "1.0"
/*============引用接口库文件并进行测试床初始化===================*/
eval(Include("D:\\cyl\\Security&×××\\security.js"));
/*===测试脚本头部分:说明测试目的、功能概述并记录日志================*/
HEAD("1.1.1 防火墙部分NAT模块SNAT基本功能测试","CHEYL 7765 2010-1-10");
/*=======基本配置部分:连接设备并完成命令行配置====================*/
sessionConnect(map.mapDevSess("DUT","s"));
setPcp("pcp","source-ip","net",map.mapInt("DUT1","PORT1",true,false),\
map.mapInt("DUT1","PORT1",false,true);
setSnatIp("pcp",map.mapInt("DUT1","PORT1",true,false));
sessionDisconnect();
/*=======检查部分:利用Check接口完成多个step的检查并将结果记录日====*/
//步骤一:
STEP(1,"从DUT1到DUT2能不能ping通");
sessionConnect(map.mapDevSess('DUT1','s'));
Check("ping",map.mapInt("DUT","PORT1",true, false),"5","test");
Check("ping",map.mapInt("DUT2","PORT1",true, false),"5","test");
sessionDisconnect();
//步骤二:
STEP("2","从DUT1到DUT2能不能ping通");
sessionConnect(map.mapDevSess("DUT2","s"));
Check("ping",map.mapInt("DUT1","PORT1",true, false),"5","test");
Check("ping",map.mapInt("DUT","PORT1",true, false),"5","test");
sessionDisconnect();
/*===========配置清除部分:将配置清除为初始化=====================*/
sessionConnect(map.mapDevSess("DUT","s"));
removePcp("pcp");
removeSnat("pcp");
sessionDisconnect();
/*=======================脚本结束==============================*/
从上面的脚本可以看出一个完整的测试脚本有如下几部分组成:
1. 脚本语言及版本说明(作为单独的脚本执行时是必须的否则需要注释掉)
2. 脚本头文件:说明测试目的、功能概述、作者及日期等并记录日志
3. 基本配置部分:连接设备并完成命令行配置。该部分如果多个测试脚本共用可以移到测试集拓扑文件映射过程中。
4. 检查部分:利用Check接口完成多个step的检查并将结果记录日志。
5. 配置清除部分:将配置清除为初始化。目的是为了防止相关配置对后续功能检查的影响。相关配置清除之后脚本执行也就结束了。
6. 除了以上5点之外最重要的就是记录日志:在脚本执行的过程之中会将相关步骤、脚本的执行结果记录在日志中,如果检查失败还会记录失败信息便于定位。

2.4 测试集

同一个模块的相关测试脚本完成后便可以生成一个测试集文件。不同模块的测试集文件也可以放在一起生成一个总的测试集文件。这样做的目的便于管理。下面就是一个测试集文件的实例:
# $language = "JScript"
# $interface = "1.0"
/*======引用接口库文件并进行测试床初始化================*/
eval(Include("D:\\cyl\\Security&×××\\BaseLIB.js"));
/*=======读取测试床文件并完成设备初始化=================*/
MODULE_TEST_SUIT_START();
/*========测试集文件:包含各个脚本文件并执行============*/
eval(Include("D:\\cyl\\Security&×××\\script1.js"));
eval(Include("D:\\cyl\\Security&×××\\script2.js"));
MODULE_TEST_SUIT_END()
分析上述测试集文件可以看出包含如下几个步骤:
1. 脚本语言及版本说明。
2. 引用接口库文件。库文件中包含了各个模块的接口。因为其规模较大,可以按模块划分后综合,这样便于问题定位及管理。
3. 读取测试床文件并完成设备初始化。整个测试集执行过程中只进行一次测试床文件解析及物理组网初始化。
4. 测试集文件:包含各个脚本文件并顺序执行。
5. 测试集执行结束完成测试结果的汇总。这个过程会有一个很重要的功能,那就是生成测试结果。以邮件的方式发送到管理员邮箱之中。具体日志格式及邮件格式请参见脚本日志设计章节。
以上几部分分别较为详细的介绍了NATF自动化测试框架的各个组成部件。但是并没有涉及到具体的实现。下面将较为详细的介绍一下具体的实现及相关的脚本的写作规范。

第3章 脚本接口设计规范

因为我司普遍采用了SecureCRT作为测试平台,而SecureCRT只提供了Jscript、VBscript及PerlScript三种脚本语言。而没有提供业界用的较多的tcl&tk脚本语言,所以只能选择Jscript语言。我们的网络设备的测试都是基于命令行的,所以自动化实现主要是完成配置命令的下发与功能的检查两部分。
要完成模块配置的下发,就需要将命令行进行包装,结合SecureCRT简单的脚本功能开发出适合我司设备的接口库,然后用这些接口库文件编写脚本实现自动化测试。
目前接口库的接口设计主要有三类:set类、get类和chk类三种。每个接口均为一个函数,主要包括两个方面:1.接口说明,需要说明函数功能,参数、作者、日期、返回值及应用举例等。2.函数体:主要实现相关功能。下面分别进行说明。

3.1 set/remove类

Set类接口主要完成配置的下发。
举例如下:
//*********************************************************************
//函数功能:通过执行“interface Ge0/0/0 ”配置设备接口
//函数参数:arg1--删除的接口名
// arg2--厂商标识(s为思科,h为华为,默认为网御)
//作 者 :cheyl 2009-12-20
//返回值 :配置正确返回true,否则为false
//举 例: setInt("Ge0/0/0")
//*********************************************************************
function setInt(arg)
{
var viewTemp = new view();
viewTemp.viewCfg();
crt.screen.send("interface " + arg + "\r");
if(crt.screen.waitforstring("\(config-if\)#"))
{
return true;
}
return false;
}
Remove主要完成配置的删除,一般情况下跟set类是成对出现的,共同完成某个命令的下发与删除。
Remove类举例如下:
//*********************************************************************
//函数功能:通过执行undo interface Ge0/0/0 删除设备逻辑接口,物理接口不可删
//函数接口:arg2---厂商标识(s为思科,h为华为,默认为网御)
//作 者 :cheyl 2009-12-20
//返回值 :配置正确返回true,否则为false
//举 例: removeInt("Ge0/0/0")
//*********************************************************************
function removeInt(arg1,arg2)
{
var viewTemp = new view();
viewTemp.viewCfg();
switch(arg2)
{
case "s":
crt.screen.send("no interface " + arg1 + "\r\n");
crt.screen.WaitForString("#");
break;
case "h":
crt.screen.send("undo interface " + arg1 + "\r\n");
crt.screen.WaitForString("#");
break;
default:
crt.screen.send("undo interface " + arg1 + "\r\n");
crt.screen.WaitForString("#");
break;
}
if(crt.screen.waitforstring("\(config\)#"))
{
return true;
}
return false;
}

3.2 get类接口

get类接口主要完成show信息的获取,get是chk的基础,chk一般会通过get类得到
信息经过比较,处理后以便确定模块的功能的正确性。
//************************************************************************
//函数功能:通过执行“show int f0/0 ”来获取某个接口的相关ip信息
//函数接口:arg1---接口
// arg2---需要获取的信息(ip、mask、state、mac、speed、mtu、duplex、
// input、output)
// arg3---厂商选择
//作 者:cheyl 2009-12-20
//返回值 :配置正确返回true,否则为false
//举 例: getIntInfo("f0/0","output","s");
//************************************************************************
function getIntInfo(arg1,arg2,arg3)
{
var rowTemp,result,resultTemp;
var viewTemp = new view();
var regTempIp = RegExp("(\\d{1,3}\.){3}\\d{1,3}");
var regTempMask = RegExp("/\\d*");
var regTempState = RegExp("\\bdown\\b|\\bup\\b");
var regTempMac = RegExp("(\\w{4}\.){3}");
var regTempSpeed = RegExp("10{1,4}");
var regTempMtu = RegExp("\\d+");
var regTempDuplex = RegExp("half|full","i");
var regTempInOutStatistcs = RegExp("\\d*");
var regTempConfig = RegExp("config");
switch(arg3)
{
case "s":
resultTemp = getIntInfoCisco();
break;
case "h":
resultTemp = getIntInfoH3c();
break;
default:
resultTemp = getIntInfoLeadsec();
break;
}
function getIntInfoCisco()
{
var rowTemp = crt.screen.CurrentRow;
var result = crt.screen.get(rowTemp, 1, rowTemp, 80);
var resultTemp;
if(regTempConfig.exec(result))
{
crt.screen.send("end"+"\r");
crt.screen.WaitForString("#");
}
crt.screen.send("show interface " + arg1 + "\r\r\r\r");
crt.screen.WaitForString("#");
var row = crt.screen.CurrentRow;
//arg1 = {ip、mask、state、mac、speed、mtu、duplex、input、output}
//regexp = regTempIpMask,regTempState,regTempMac,regTempSpeed,regTempMtu,regTempDuplex,regTempInOutStatistcs
switch(arg2)
{
case "ip":
result = crt.screen.get(row-24, 1, row-24, 80);
resultTemp = result.match(regTempIp)[0];
break;
case "mask":
result = crt.screen.get(row-24, 1, row-24, 80);
resultTemp = result.match(regTempMask).toString().split("/")[1];
break;
case "state":
result = crt.screen.get(row-26, 1, row-26, 80);
resultTemp = result.match(regTempState);
break;
case "mac":
result = crt.screen.get(row-25, 1, row-25, 80);
resultTemp = result.match(regTempMac)[0];
break;
case "speed":
result = crt.screen.get(row-19, 1, row-19, 80);
resultTemp = result.match(regTempSpeed)[0];
break;
case "mtu":
result = crt.screen.get(row-23, 1, row-23, 80);
resultTemp = result.match(regTempMtu)[0];
break;
case "duplex":
result = crt.screen.get(row-19, 1, row-19, 80);
resultTemp = result.match(regTempDuplex)[0];
break;
case "input":
result = crt.screen.get(row-10, 6, row-10, 80);
resultTemp = result.match(regTempInOutStatistcs);
break;
case "output":
result = crt.screen.get(row-5, 6, row-5, 80);
resultTemp = result.match(regTempInOutStatistcs);
break;
default:
break;
}
return resultTemp;
}
function getIntInfoH3c()
{
var rowTemp = crt.screen.CurrentRow;
var result = crt.screen.get(rowTemp, 1, rowTemp, 80);
var resultTemp;
if(regTempConfig.exec(result))
{
crt.screen.send("end"+"\r");
crt.screen.WaitForString("#");
}
crt.screen.send("show interface " + arg1 + "\r\r\r\r");
crt.screen.WaitForString("#");
var row = crt.screen.CurrentRow;
//arg1 = {ip、mask、state、mac、speed、mtu、duplex、input、output}
//regexp = regTempIpMask,regTempState,regTempMac,regTempSpeed,regTempMtu,regTempDuplex,regTempInOutStatistcs
switch(arg2)
{
case "ip":
result = crt.screen.get(row-24, 1, row-24, 80);
resultTemp = result.match(regTempIp)[0];
break;
case "mask":
result = crt.screen.get(row-24, 1, row-24, 80);
resultTemp = result.match(regTempMask).toString().split("/")[1];
break;
case "state":
result = crt.screen.get(row-26, 1, row-26, 80);
resultTemp = result.match(regTempState);
break;
case "mac":
result = crt.screen.get(row-25, 1, row-25, 80);
resultTemp = result.match(regTempMac)[0];
break;
case "speed":
result = crt.screen.get(row-19, 1, row-19, 80);
resultTemp = result.match(regTempSpeed)[0];
break;
case "mtu":
result = crt.screen.get(row-23, 1, row-23, 80);
resultTemp = result.match(regTempMtu)[0];
break;
case "duplex":
result = crt.screen.get(row-19, 1, row-19, 80);
resultTemp = result.match(regTempDuplex)[0];
break;
case "input":
result = crt.screen.get(row-10, 6, row-10, 80);
resultTemp = result.match(regTempInOutStatistcs);
break;
case "output":
result = crt.screen.get(row-5, 6, row-5, 80);
resultTemp = result.match(regTempInOutStatistcs);
break;
default:
break;
}
return resultTemp;
}
function getIntInfoLeadsec()
{
var rowTemp = crt.screen.CurrentRow;
var result = crt.screen.get(rowTemp, 1, rowTemp, 80);
var resultTemp;
if(regTempConfig.exec(result))
{
crt.screen.send("end"+"\r");
crt.screen.WaitForString("#");
}
crt.screen.send("show interface " + arg1 + "\r\r\r\r");
crt.screen.WaitForString("#");
var row = crt.screen.CurrentRow;
//arg1 = {ip、mask、state、mac、speed、mtu、duplex、input、output}
//regexp = regTempIpMask,regTempState,regTempMac,regTempSpeed,regTempMtu,regTempDuplex,regTempInOutStatistcs
switch(arg2)
{
case "ip":
result = crt.screen.get(row-6, 1, row-6, 80);
resultTemp = result.match(regTempIp)[0];
break;
case "mask":
result = crt.screen.get(row-6, 1, row-6, 80);
resultTemp = result.match(regTempMask).toString().split("/")[1];
break;
case "state":
result = crt.screen.get(row-10, 1, row-10, 80);
resultTemp = result.match(regTempState);
break;
case "mac":
result = crt.screen.get(row-5, 1, row-5, 80);
resultTemp = result.match(regTempMac)[0];
break;
case "speed":
result = crt.screen.get(row-4, 1, row-4, 80);
resultTemp = result.match(regTempSpeed)[0];
break;
case "mtu":
result = crt.screen.get(row-8, 1, row-8, 80);
resultTemp = result.match(regTempMtu)[0];
break;
case "duplex":
result = crt.screen.get(row-4, 1, row-4, 80);
resultTemp = result.match(regTempDuplex)[0];
break;
case "input":
result = crt.screen.get(row-3, 6, row-3, 80);
resultTemp = result.match(regTempInOutStatistcs);
break;
case "output":
result = crt.screen.get(row-1, 6, row-1, 80);
resultTemp = result.match(regTempInOutStatistcs);
break;
default:
break;
}
return resultTemp;
}
return resultTemp;
}

3.3 chk类接口

Chk类接口则可以完成相关功能的检查。举例如下:
//************************************************************************
//函数功能:通过执行“ping x.x.x.x ”测试设备的连通性
//函数接口:
// arg 必选 标识了ping的ip地址
//作 者:cheyl 2009-12-20
//返回值 :ping成功了返回1,失败了返回0
//举 例: chkPing("1.1.1.1")
//************************************************************************
function chkPing(arg1,arg2)
{
var viewTemp = new view();
crt.screen.Synchronous = true;
crt.screen.send("\n");
var row = crt.screen.CurrentRow;
result = crt.screen.get(row, 1, row, 33);
var regTemp = new RegExp("config");
var regTemps = new RegExp("[0-9]{1,3}");
var regTempl = new RegExp("^[0-9].*,$");
switch(arg2)
{
case "s":
if(regTemp.test(result))
{
crt.screen.send("end" + "\r\n");
crt.screen.WaitForString("#");
}
crt.screen.send("ping " + arg1 + "\r\n");
crt.screen.WaitForString("#");
row = crt.screen.CurrentRow;
result = crt.screen.get(row-1, 1, row-1, 33);
if(regTemps.exec(result)>=20)
{
return true;
}
return false;
break;
case "h":
crt.screen.send("ping " + arg1 + "\r\n");
crt.screen.WaitForString("#");
break;
default:
viewTemp.viewDia();
crt.screen.send("ping " + arg1 + "\r\n");
crt.screen.WaitForString("#");
row = crt.screen.CurrentRow;
result = crt.screen.get(row-1, 1, row-1, 33);
if(regTempl.exec(result).split(" ")[0]>=2)
{
return true;
}
return false;
break;
}
crt.screen.Synchronous = false;
}

第4章 脚本功能检查的实现

根据命令行手册完备以上set/remove、get、chk三种类型的接口就可以完成模块配置工作。那么功能正确性检查工作一般采用CHECK接口来完成,具体的CHECK可以分为三种:
Ping方式的检查、route路由检查和custom自定义检查。最常用的是ping和custom两种。下面是Check接口函数的说明。
clip_p_w_picpath003
//*****************************************************************************
//函数功能:本接口用来进行相关的检查?
//函数接口:arg1---需要检查的方法,包括ping、route、custom三种
// arg2---检查项,包括ping的ip地址,custom自定义的检查等
// repeat---失败后的重复检查次数
// whenfailed---失败后需要的定位信息
//作 者:cheyl 2009-12-29
//返回值 :无
//举 例: Check("ping","5","1.1.1.1","test");
//说 明:上述检查ping 1.1.1.1如果失败会重复检查5次,五次都失败后在日志文件中
// 记录相关定位信息,当然也可以直接在Check接口的whenfailed参数处直接输
// 入crt.dialog.messagebox();进行输出定位
//*****************************************************************************
从上面的说明可以看出CHECK函数有4个参数,arg1就是需要制定的检查的方法。Arg2分别对应了ping检查的ip地址和custom自定义检查的代码。这里边需要注意的是custom方式的检查其实是利用了chk类接口的检查。最后一个chk类的返回值也就是对应的Check的返回值。Arg3指定了检查失败后的重复检查次数,设置这个参数是为了规避因为环境等因素造成的错误检查。Arg4参数可以允许用户自定义检查失败后的相关信息,一般可以将get类接口的返回值输出到日志中便于定位问题。

4.1 ping型检查

ping型检查是最简单也是最常用的检查类型,可以用来定位网络的连通性,而且许多
功能如NAT,IPSEC等都可以通过ping来触发相关功能。进而生成会话session,nat转换表,ipsec sa表等检查信息,然后通过判断这些信息的正确性进一步来确定模块功能的正确性。

4.2 custom型检查

Custom型检查也称为自定义类型的检查。Ping检查只能完成ping的功能,而custom的输入不再是单纯的ip地址而是一段可执行的脚本代码,可以在配置基础上进行检查。Custom型的检查一般依赖于chk接口,检查一般也以chk类或有返回值的接口结尾,利用chk可以完成某个功能正确性检查的特点完成检查并返回检查结果。
举个例子,某个脚本需要进行SNAT基本功能的检查,自动化工程师写了一个chkSnat的接口,在该接口中利用session中SNAT的信息判断SNAT的正确性,那么在检查的过程中就可以采用custom检查。具体检查如下:
CHECK("custom","5"," setPcp(‘pcp’,’source-ip’,’net’,map.mapInt(‘DUT1’,’PORT1’,true,false),map.mapInt(‘DUT1’,’PORT1’,false,true);setSnatIp(‘pcp’,map.mapInt(‘DUT1’,’PORT1’,true,false));chkSnat();","test");
上面CHECK中绿色的部分便是自定义部分,配置了PCP、SNAT然后用chkSnat接口
完成检查。

4.3 route型检查

route类型的检查在防火墙的测试中很少用到,主要用来检查静态、动态路由的正确性。
比如说全网启用了ospf动态路由协议,等待全网收敛之后呢就会在路由表中生成响应的路由信息,route型检查便利用了这一点,通过检查目的IP是否在路由表中来确定路由功能的正确性以及网络的联通性。

第5章 脚本日志设计规范

在测试集执行过程中每一个测试脚本的每一个步骤的检查过程及结果都会被记录到动态生成的日志文件中。最终生成的日志文件包含两种:

5.1 日志:*.log型

clip_p_w_picpath005
LOG型日志主要目的在于记录脚本情况、测试网络、测试过程及测试结果。这三部分主要体现在如下方面:记录脚本功能作者日期等信息反映脚本概况;记录逻辑拓扑和测试床的映射结果来反映测试网络;记录每一步骤的检查情况跟踪测试过程;根据每一步检查结果整合输出测试结果。

5.2 报表:*.exl型

clip_p_w_picpath007
EXL型的日志不包括测试过程只是LOG日志结果的一个更加鲜明的展示。
当测试集执行完毕之后系统会自动通过邮件方式将测试结果发送到管理员邮箱之中。管理员上班时打开邮箱就可以看到测试结果了。根据日志进行分析,确认定位相关问题。

第6章 脚本中如何实现报文收发

Smartbits及avlanche均提供了相关的操作接口。但是这些接口均是采用了tcl语言写的,但是当前securecrt平台不支持tcl语言,所以要实现自动化Smartbits收发包需要扩展,让Jscript识别tcl语句,这一点当前无法做到。
另外一种方法就是利用当前已经存在大量的基于linux/Windows的收发包工具。且多为命令行形式。这样一来便可以用securecrt通过telnet到linux主机上进行收发包操作。这样便可以解决测试脚本中的流量问题。 6.1 利用SmartLib接口库实现
利用思博伦提供的SmartLib接口库便可以实现SmartBit及avlanche的收发包。该种
方法较为灵活,可以设置多种收发包模式,也可以自定义流量及报文细节。但是当前SecureCRT不支持TCL语言所以暂时无法实现该种方式的收发包。
附件:
clip_p_w_picpath009clip_p_w_picpath011clip_p_w_picpath013

6.2 利用linux/window收发包工具实现

另外一种方法就是利用现有的linux/windows收发包工具,当前大家用的较多的有
Iperf、hping两种。两种工具均有window和linux的版本,且均为命令行操作。这样便于采用脚本来管理。
clip_p_w_picpath015 clip_p_w_picpath017
另外需要说明的是在Jscript脚本中可以采用WScript.Shell来实现window下批处理文件的执行。
附件:NATF实现接口及相关文件
clip_p_w_picpath019
  • 收藏
  • 评论
  • 举报
提问和评论都可以,用心的回复会被更多人看到 评论
发布评论
相关文章