一个数据库中包含的功能及语法非常庞大,如果是按照语法手动输入测试会非常繁琐且易出错。TCL脚本广泛应用于自动化测试,快速原型开发,脚本编程, GUI等各个方面。例如,Spirent TestCenter就是基于TCL进行网络设备测试的。
expect是Unix系统中用来进行自动化控制和测试的软件工具,应用在交互式软件中如telnet,ftp,Passwd,fsck,rlogin,tip,ssh等等。在deepin下,远程登录就是利用expect实现的。在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是expect。expect是由tcl语言演变而来的,所以expect脚本的运行需要tcl的支持。安装tcl和expect的步骤略,请自行查找安装方式。
expect基本命令:
send
用于向进程发送字符串send命令接收一个字符串参数,并将该参数发送到进程。
expect
从进程接收字符串expect命令和send命令相反,expect通常用来等待一个进程的反馈,我们根据进程的反馈,再发送对应的交互命令。
spawn
启动新的进程spawn命令用来启动新的进程,spawn后的send和expect命令都是和使用spawn打开的进程进行交互。
interact
允许用户交互interact命令用的其实不是很多,一般情况下使用spawn、send和expect命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用interact命令的,interact命令主要用于退出自动化,进入人工交互。
参考下面脚本:
#!/usr/bin/expect
set timeout 30
set host "192.168.1.215"
set username "root"
set password "123456"
spawn ssh $username@$host
expect "*password*" {send "$password\r"}
interact
#!/usr/bin/expect
使用expect来解释这个脚本。
set timeout 30
设置超时时间,单位是秒,默认是10秒,这里设置了30秒超时。
set host "192.168.1.215"
、set username "root"
、set password "123456"
设置host、username、password变量。
spawn ssh $username@$host
spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。它主要的功能是给ssh运行进程加个壳,用来传递交互指令;
expect "*password*"
这里的expect也是expect的一个内部命令,这个命令的意思是判断上次输出结果里是否包含“password”的字符串,如果有则立即返回;否则就等待一段时间后返回,这里等待时长就是前面设置的30秒;
send "$password\r"
当匹配到对应的输出结果时,就发送密码到打开的ssh进程,执行交互动作;
interact
执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。
很简单的expect脚本,就是设定好的用户名、密码登录服务器,实现了类似于xshell记录用户名密码进行自动登录的功能。
但这里包含了expect一个重要的概念,模式-动作。
expect "*password*" {send "$password\r"}
即是模式-动作的代表,简单来说就是匹配一个模式,匹配到就执行对应的动作。在这里,就是匹配命令行输出password
字符串,如果有,就输入密码。
复杂一点的例子:
expect {
"password" {
send "$password\r"
exp_continue
}
eof
{
send "eof"
}
}
其中exp_continue表示循环式匹配,通常匹配之后都会退出语句,但如果有exp_continue则可以不断循环匹配,输入多条命令,简化写法。
很多时候,我们需要传递参数到脚本中,现在通过下面这段代码来看看如何在expect中使用参数:
#!/usr/bin/expect
if {$argc < 3} {
puts "Usage:cmd <host> <username> <password>"
exit 1
}
set timeout -1
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $username@$host
expect "*password*" {send "$password\r"}
interact
在expect中,$argc表示参数个数count,而参数值存放在$argv中,比如取第一个参数就是[lindex $argv 0],以此类推。
TCL和expect详细的参考文档请参考Expect and TCL mini reference manual
test.tcl:
#! /usr/bin/env expect -f
source [file join [file dirname $argv0] common.tcl]
start_test "Check that demo says hello properly"
spawn $argv demo
eexpect "Welcome"
eexpect "your changes to data stored in the demo session will not be saved!"
eexpect "Web UI: http:"
eexpect "Server version"
eexpect "Cluster ID"
eexpect "brief introduction"
eexpect root@
eexpect "movr>"
end_test
这个脚本依赖于common.tcl
,在common.tcl中定义了一些公用调用proc,例如这个例子中的eexpect
,就是在common.tcl中定义的。
proc eexpect {text} {
expect {
$text {}
timeout { handle_timeout $text }
}
}
eexpect用于匹配字符串,并处理timeout。start_test
,end_test
也是common中定义的输出文本语句。
实际测试时使用 expect -f path/to/test.tcl path/to/hubble
所以在spawn $argv demo
时,会运行hubble demo
命令。
之后就是校验输出,确定进入的库等信息。
如果是校验具体的SQL,可以添加
send "select count(*) from t.foo;\r"
eexpect "0"
即可校验t.foo表的count值是否符合预期。
持续更新自动化测试部分代码,尽量使测试覆盖的范围更广。