Robot Framework+SSHLibrary介绍
首先,介绍一下robotframework,oschina这么介绍:
Robot Framework 是一个关键词驱动的自动测试框架。测试用例位于HTML或者TSV(以tab分隔值)文件,使用在测试库中实现的关键词来在测试中运行程序。因为 Robot Framework 是灵活和可扩展的,所以它很合适用于测试具有多种接口的复杂软件:用户接口,命令行,webservice,编程接口等。
Robot Framework 和 Cumcumber http://www.oschina.net/p/cucumber 具有相似的能力,都属于BDD自动化测试工具。 但是Cumcumber只能顺序验证测试步骤,比如:
Given 我在登录页
When 我输入帐号"zhangsan"
And 我输入密码"123456"
And 我点击登录按钮
Then 我能看到我的昵称"张三"
上述的 "我在登录页" 等步骤的定义,都在Cumcumber的step_definitions.rb中,用ruby语言定义。
如果对Cumcumber测试安卓手机APP感兴趣,可以参阅 使用calabash测试开源中国Android客户端
Robot Framework在语义级别就提供了FOR循环和IF判断,自定义Keyword直接在.robot文件中,不需要写一句Python语句。
然后再去官网 http://robotframework.org/ ,到TestLibraries看看都提供了什么测试库:
STANDARD库中包含OperatingSystem,String,Collections,提供了调用本地shell命令,字符串处理,和Python集合的处理能力。
EXTERNAL库中有手机APP测试相关的测试库、网页测试相关、http测试相关、数据库相关、ssh相关。
我最看中的就是其中SSHLibrary,它提供ssh登录和执行远程命令的能力,并能用sftp上传下载文件。
SSHLibrary对python库paramiko进行了封装,所以他是Farbric的兄弟,Fabric常用于自动化运维,但是缺少对运维结果的检测能力。
所以,Robot Framework+SSHLibrary天生就适合做网站的自动化运维质量检测。
自动化运行质量检测,包含那些内容?
- mysql, mongo, nginx等工具的配置是否正确
- mysql, mongo, nginx等工具的进程是否已崩溃
- mysql, mongo, nginx的数据等目录的owner是否正确
- 网站服务器各结点的网络配置是否正确
- 各tomcat, jetty服务的版本是否符合预期
后面通过一个一个的小例子,来演示Robot Framework+SSHLibrary怎样达到自动化运维质量检测
Debian/Ubunbu下安装Robot Framework+SSHLibrary
Python默认已安装
pip: python环境下模块安装工具
sudo apt-get install python-pip
python-dev: 某些python模块安装需要Python.h,所以要安装python-dev
sudo apt-get install python-dev
robotframework: http://robotframework.org
sudo pip install robotframework
如果使用默认pip源很慢,可以指定豆瓣的pip源:
sudo pip install robotframework -i http://pypi.douban.com/simple
SSHLibrary: https://github.com/robotframework/SSHLibrary
pip install robotframework-sshlibrary
Redhat/CentOS 下安装Robot Framework+SSHLibrary
只要把Debian对应安装命令中的apt-get 改成yum, dev改成devel Python默认已安装
pip: python环境下模块安装工具
sudo yum install python-pip
python-devel: 某些python模块安装需要Python.h,所以要安装python-devel
sudo yum install python-devel
robotframework: http://robotframework.org
sudo pip install robotframework
SSHLibrary: https://github.com/robotframework/SSHLibrary
pip install robotframework-sshlibrary
RobotFramework+SSHLibrary远程调用命令示例
示例来自: http://robotframework.org/SSHLibrary/
注意:
- 下面的${HOST}, ${USERNAME}, ${PASSWORD} 请使用自己远程机器名、帐号和密码
- 还要确保远程机器已经开启了sshd服务
测试用例文件:
shen@debian:~/robotframework$ cat executing-commands.robot
*** Settings ***
Documentation This example demonstrates executing commands on a remote machine
... and getting their output and the return code.
...
... Notice how connections are handled as part of the suite setup and
... teardown. This saves some time when executing several test cases.
Library SSHLibrary
Suite Setup Open Connection And Log In
Suite Teardown Close All Connections
*** Variables ***
${HOST} localhost
${USERNAME} shen
${PASSWORD} 123456
*** Test Cases ***
Execute Command And Verify Output
[Documentation] Execute Command can be used to ran commands on the remote machine.
... The keyword returns the standard output by default.
${output}= Execute Command echo Hello SSHLibrary!
Should Be Equal ${output} Hello SSHLibrary!
Execute Command And Verify Return Code
[Documentation] Often getting the return code of the command is enough.
... This behaviour can be adjusted as Execute Command arguments.
${rc}= Execute Command echo Success guaranteed. return_stdout=False return_rc=True
Should Be Equal ${rc} ${0}
Executing Commands In An Interactive Session
[Documentation] Execute Command always executes the command in a new shell.
... This means that changes to the environment are not persisted
... between subsequent Execute Command keyword calls.
... Write and Read Until variants can be used to operate in the same shell.
Write cd ..
Write echo Hello from the parent directory!
${output}= Read Until directory!
Should End With ${output} Hello from the parent directory!
*** Keywords ***
Open Connection And Log In
Open Connection ${HOST}
Login ${USERNAME} ${PASSWORD}
gedit打开executing-commands.robot的效果:
执行结果:
shen@debian:~/robotframework$ pybot executing-commands.robot
==============================================================================
Executing Commands :: This example demonstrates executing commands on a rem...
==============================================================================
Execute Command And Verify Output :: Execute Command can be used t... | PASS |
------------------------------------------------------------------------------
Execute Command And Verify Return Code :: Often getting the return... | PASS |
------------------------------------------------------------------------------
Executing Commands In An Interactive Session :: Execute Command al... | PASS |
------------------------------------------------------------------------------
Executing Commands :: This example demonstrates executing commands... | PASS |
3 critical tests, 3 passed, 0 failed
3 tests total, 3 passed, 0 failed
==============================================================================
Output: /home/shen/robotframework/output.xml
Log: /home/shen/robotframework/log.html
Report: /home/shen/robotframework/report.html
Robot Framework+SSHLibrary实现自动化运维质量检测
example-100: 直接在命令行输入ssh密码
为了能方便演示,每个例子都有各编号如100,对应的代码目录~/robotframework/100 上述基本ssh例子先简化如下:
shen@debian:~/robotframework/100$ cat example-100.robot
*** Settings ***
Documentation ssh示例
Library SSHLibrary
Suite Setup Open Connection And Log In
Suite Teardown Close All Connections
*** Variables ***
${HOST} localhost
${USERNAME} shen
${PASSWORD} 123456
*** Test Cases ***
远程执行命令并检验输出
${output}= Execute Command echo Hello SSHLibrary!
Should Be Equal ${output} Hello SSHLibrary!
*** Keywords ***
Open Connection And Log In
Open Connection ${HOST}
Login ${USERNAME} ${PASSWORD}
说明: 上述检验内容是ssh到localhost,执行shell命令: echo Hello SSHLibrary!
,
应该看到stdout为 Hello SSHLibrary!
下面用手工执行ssh来模拟上述检验:
在使用if判断变量output时,碰到了单引号和双引号的替换规则问题,而且bash的if-else-fi真心难写。
只有下面if中的单双引号使用是正确的:
if [ "$output" == 'Hello SSHLibrary!' ]; then echo -e "| \033[32mPASS\033[0m |"; else echo -e "| \033[31mFAIL\033[0m |"; fi
回到正题,我想在pybot命令行直接输入ssh密码,可以这样执行:
因为输入的是错误密码,所以提示: Authentication failed for user 'shen'.
规则1: pybot命令行中输入的变量值会覆盖robot文件中*** Variables ***
中定义的变量值
example-110: 执行测试时打印调试信息
上面的example-100.robot运行时,屏幕上只打印了testcase名称和测试结果绿色PASS或红色FAIL。
在运行目录下生成了3个文件:output.xml, log.html, report.html,先分别打开看看:
我不习惯去看html文件,所以我想在运行时直接打印output变量的内容。
先去官网找到Log To Console的帮助信息: http://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Log%20To%20Console
官网帮助中的robotframework测试用例格式都是表格,但是最实用的是txt格式,测试用例文件的后缀可以是.txt或.robot
表格格式的分隔方式就是一个一个格子,txt格式对应分隔符是两个以上空格或者一个以上Tab。
shen@debian:~/robotframework/110$ cat example-110.robot
*** Settings ***
Documentation ssh示例
Library SSHLibrary
Suite Setup Open Connection And Log In
Suite Teardown Close All Connections
*** Variables ***
${HOST} localhost
${USERNAME} shen
${PASSWORD} 123456
*** Test Cases ***
远程执行命令并检验输出
${output}= Execute Command echo Hello SSHLibrary!
Log To Console \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"
Should Be Equal ${output} Hello SSHLibrary!
*** Keywords ***
Open Connection And Log In
Open Connection ${HOST}
Login ${USERNAME} ${PASSWORD}
请注意新增行:
Log To Console \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"
执行测试结果:
说明: \x1b[1;33m${output}\x1b[0m 是以高亮黄色打印变量${output}的内容。\x1b与echo打印彩色时的\033是相同的。
但是robotframework测试用例文件的语法中不支持\0nn八进制,只支持\xnn 十六进制。 Log To Console右边必须先输入两个以上空格或1个以上Tab,再输入变量;两个变量之间也要如此分隔。
规则2: robotframework测试用例文件中字符$要用$转义,\xnn指定十六进制字符。
example-120: 我要把服务器的结点信息保存在外部文件中
首先看一下pybot的-h帮助: 执行命令: pybot -h
,其中的-v参数可以指定一个变量的值,-V可以从一个文件中指定多个变量。
shen@debian:~/robotframework/120$ cat node-list.py
SSH_SERVERS = ['node01', 'node02', 'node03']
NODE_IP_MAP = {
'node01':'localhost',
'node02':'127.0.0.1',
'node03':'192.168.0.107',
}
shen@debian:~/robotframework/120$ cat example-120.robot
*** Settings ***
Documentation ssh示例
Library Collections
Library SSHLibrary
Suite Teardown Close All Connections
*** Variables ***
*** Test Cases ***
远程执行命令并检验输出
:FOR ${node} IN @{SSH_SERVERS}
\ ${node_ip}= Get From Dictionary ${NODE_IP_MAP} ${node}
\ Log To Console \n正在登录 ${node}(${node_ip}) ...
\ Open Connection And Log In "${node_ip}"
\ Log To Console \n正在${node}(${node_ip})执行命令: echo Hello SSHLibrary!
\ ${output}= Execute Command echo Hello SSHLibrary!
\ Log To Console \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"
\ Should Be Equal ${output} Hello SSHLibrary!
*** Keywords ***
Open Connection And Log In "${node_ip}"
Open Connection ${node_ip}
Login ${USERNAME} ${PASSWORD}
请注意例子120的几处新内容:
- node-list.py 定义了所有结点的ip信息和ssh服务器列表,使用python的列表和字典定义
- example-120.robot 中引入了新测试库: Collections http://robotframework.org/robotframework/latest/libraries/Collections.html
- 重新定义了关键字:Open Connection And Log In,可以接受参数${node_ip}
- 使用FOR循环遍历SSH_SERVERS中的每个结点。
example-130: 我要确保服务器结点的python版本都是2.7.3
shen@debian:~/robotframework/130$ cat node-list.py
PYTHON_SERVERS = ['node01', 'node03']
SSH_SERVERS = ['node01', 'node02', 'node03']
NODE_IP_MAP = {
'node01':'localhost',
'node02':'127.0.0.1',
'node03':'192.168.0.107',
}
shen@debian:~/robotframework/130$ cat versions.py
VERSIONS = {
'python':'2.7.3',
'gcc':'4.7.2',
'ssh':'OpenSSH_6.0p1',
}
shen@debian:~/robotframework/130$ cat example-130.robot
*** Settings ***
Documentation ssh示例
Library Collections
Library SSHLibrary
Suite Teardown Close All Connections
*** Variables ***
*** Test Cases ***
远程执行命令并检验输出
:FOR ${node} IN @{SSH_SERVERS}
\ ${node_ip}= Get From Dictionary ${NODE_IP_MAP} ${node}
\ Log To Console \n正在登录 ${node}(${node_ip}) ...
\ Open Connection And Log In "${node_ip}"
\ Log To Console \n正在${node}(${node_ip})执行命令: echo Hello SSHLibrary!
\ ${output}= Execute Command echo Hello SSHLibrary!
\ Log To Console \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"
\ Should Be Equal ${output} Hello SSHLibrary!
检查python版本
:FOR ${node} IN @{PYTHON_SERVERS}
\ ${node_ip}= Get From Dictionary ${NODE_IP_MAP} ${node}
\ Open Connection And Log In "${node_ip}"
\ Log To Console \n正在${node}(${node_ip})执行命令: python --version 2>&1 | cut -d' ' -f 2
\ ${output}= Execute Command python --version 2>&1 | cut -d' ' -f 2
\ ${version}= Get From Dictionary ${VERSIONS} python
\ Log To Console \npython版本${output} == 期望版本${version} ?
\ Should Be Equal ${output} ${version}
*** Keywords ***
Open Connection And Log In "${node_ip}"
Open Connection ${node_ip}
Login ${USERNAME} ${PASSWORD}
执行测试命令:
pybot -v USERNAME:shen -v PASSWORD:123456 -V node-list.py -V versions.py example-130.robot
如果更改期望版本为2.6.6:
shen@debian:~/robotframework/130$ cat versions.py
VERSIONS = {
'python':'2.6.6',
'gcc':'4.7.2',
'ssh':'OpenSSH_6.0p1',
}
测试结果如下:
因为测试用例“检查python版本”中的第一个结点的python版本检查断言:Should Be Equal ${output} ${version}
失败,
所以robotframework直接退出本测试用例的执行,不会再去检查第二个结点的python版本。
example-140: 检查交互式输出的内容
shen@debian:~/robotframework/140$ cat example-140.robot
*** Settings ***
Documentation 交互式检查python版本
Library Collections
Library SSHLibrary
Suite Teardown Close All Connections
*** Variables ***
*** Test Cases ***
交互式检查python版本
:FOR ${node} IN @{PYTHON_SERVERS}
\ ${node_ip}= Get From Dictionary ${NODE_IP_MAP} ${node}
\ Open Connection And Log In "${node_ip}"
\ Write python
\ ${output}= Read Until >>>
\ Log To Console \n${node}(${node_ip})执行命令python的输出:---\n${output}\n---
\ ${version}= Get From Dictionary ${VERSIONS} python
\ Log To Console \n${node}(${node_ip})的python版本 == ${version} ?
\ Should Contain ${output} ${version}
*** Keywords ***
Open Connection And Log In "${node_ip}"
Open Connection ${node_ip}
Login ${USERNAME} ${PASSWORD}
执行测试结果:
example-150: 关键字定义放在独立文件中
shen@debian:~/robotframework/150$ cat keywords.robot
*** Settings ***
Library Collections
Library SSHLibrary
*** Keywords ***
Check Python Version "${servers}" "${version}"
:FOR ${node} IN @{servers}
\ ${node_ip}= Get From Dictionary ${NODE_IP_MAP} ${node}
\ Open Connection ${node_ip}
\ Login ${USERNAME} ${PASSWORD}
\ Write python
\ ${output}= Read Until >>>
\ Log To Console \n${node}(${node_ip})执行命令python的输出:---\n${output}\n---
\ Log To Console \n${node}(${node_ip})的python版本 == ${version} ?
\ Should Contain ${output} ${version}
shen@debian:~/robotframework/150$ cat example-150.robot
*** Settings ***
Documentation 交互式检查python版本
Resource keywords.robot
Suite Teardown Close All Connections
*** Variables ***
*** Test Cases ***
交互式检查python版本
${version}= Get From Dictionary ${VERSIONS} python
Check Python Version "${PYTHON_SERVERS}" "${version}"
*** Keywords ***
shen@debian:~/robotframework/150$ pybot -v USERNAME:shen -v PASSWORD:123456 -V node-list.py -V versions.py example-150.robot
==============================================================================
Example-150 :: 交互式检查python版本
==============================================================================
交互式检查python版本 .
node01(localhost)执行命令python的输出:---
Python 2.7.3 (default, Mar 13 2014, 11:03:55)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
---
node01(localhost)的python版本 == 2.7.3 ?
node03(192.168.0.107)执行命令python的输出:---
Python 2.7.3 (default, Mar 13 2014, 11:03:55)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
---
node03(192.168.0.107)的python版本 == 2.7.3 ?
交互式检查python版本 | PASS |
------------------------------------------------------------------------------
Example-150 :: 交互式检查python版本 | PASS |
1 critical test, 1 passed, 0 failed
1 test total, 1 passed, 0 failed
==============================================================================
Output: /home/shen/robotframework/150/output.xml
Log: /home/shen/robotframework/150/log.html
Report: /home/shen/robotframework/150/report.html
shen@debian:~/robotframework/150$
example-160: 执行测试的彩色打印导出到文件
复用example-150的测试用例
pybot -C on -v USERNAME:shen -v PASSWORD:123456 -V node-list.py -V versions.py example-150.robot | tee ../160/color_output.txt
后面还有什么?
欢迎大家继续提出问题,我将尽力以上述example的方式给出答案。