Python3 pexpect自动化测试
uefi reboot到打印"Press any other key in 10 seconds to stop automatical booting"时间不确定,通常情况下不会任何异常,因此此次采用pexpect默认timeout参数,用while循环等待“Press any other key in 10 seconds to stop automatical booting”,关键代码如下:
#!/usr/bin/python3
import os
import pexpect
import time
os.system('ipmitool -H %s -I lanplus -U root -P %s chassis power reset' % (ip, password))
child = pexpect.spawn('ipmitool -H %s -I lanplus -U root -P %s sol activate' % (ip, password))
index = child.expect(['Press any other key in .* seconds to stop automatical booting', pexpect.EOF, pexpect.TIMEOUT])
while (index != 0):
index = child.expect(['Press any other key in .* seconds to stop automatical booting', pexpect.EOF, pexpect.TIMEOUT])
child.sendline("")
此界面菜单顺序基本是固定的,可以通过按指定次数方向键高亮目标菜单,然而这种做法写出的脚本在不了解背景的情况下,没法看懂脚本用意,其次扩展性、可维护性不好,万一菜单有所增减或顺序调整,则脚本必须随之修改;
我们是通过ipmitool及xshell连接到arm64服务器串口,因此图3.1所示应该是字符界面;目前我们从图中可以看到,高亮菜单字体颜色及背景与其他非高亮菜单不一致,因此我们只要能expect字符串、字体颜色、背景即可定位到目标菜单,由此我们可以联想到echo控制字符,最后我们只需要获取到uefi菜单控制字符就可以了;
首先我们手动进入到3.1 uefi界面,写一测试脚本循环遍历一遍所有菜单,timeout时,打印缓存内容,从中分析获取我们需要的控制字符,脚本示例如下:
#!/usr/bin/python3
import pexpect
child = pexpect.spawn('ipmitool -H %s -I lanplus -U root -P %s sol activate' % (ip, password))
i = 0
while (i < 8):
child.sendline("v")
child.expect(['Any string', pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
print(child.before)
i = i + 1
获取到执行结果,然后再shell终端ecoh-e "..."解析控制字符串,查看执行结果,获取菜单高亮对应的字符串(去掉不必要的坐标转义字符)。
(高亮Boot Manager菜单并进入,注意:\\x1b这类字符主要为字体颜色、背景等转义字符,以及及特殊字符转义,避免与正则表达式冲突)
#!/usr/bin/python3
import pexpect
child = pexpect.spawn('ipmitool -H %s -I lanplus -U root -P %s sol activate' % (ip, password))
Boot_Manager = 'Boot Manager'
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m'% (Boot_Manager), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
while (index != 0):
child.sendline("v")
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m' % (Boot_Manager), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
child.sendline('\r\n')
菜单选择与3.2是一样的原理,4.1图示中的菜单"EFI Network"、"EFI Network 1"、"EFI Network 2"、"EFI Network 3"有包含关系,高亮"EFI Network"需要注意,正则表达式不能使用"EFI Network.*",因为这会匹配到"EFI Network 2"等,需要使用更加精确的正则表达式,当然也可以将"EFI Network1"等添加到"EFI Network"之前,例如:child.expect(['EFI Network 1', 'EFI Network 2', 'EFI Network 3', 'EFI Network', pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
#!/usr/bin/python3
import pexpect
child = pexpect.spawn('ipmitool -H %s -I lanplus -U root -P %s sol activate' % (ip, password))
efinetwork2 = 'EFI Network 2'
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m.*' % (efinetwork2), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
while (index != 0):
child.sendline("v")
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m.*' % (efinetwork2), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
child.sendline('\r\n')
(获取菜单高亮控制字符串等请参考3.2、4.2)
#!/usr/bin/python3
import pexpect
child = pexpect.spawn('ipmitool -H %s -I lanplus -U root -P %s sol activate' % (ip, password))
startup = 'Startup Estuary'
child.expect('Press .* to edit the selected item')
index = child.expect(['\\x1b\[30m\\x1b\[47m.*%s.*\\x1b\[0m\\x1b\[37m' % (startup), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
while (index != 0):
child.sendline('v')
index = child.expect(['\\x1b\[30m\\x1b\[47m.*%s.*\\x1b\[0m\\x1b\[37m' % (startup), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
child.sendline('\r\n')
#!/usr/bin/python3
import os
import pexpect
import time
ip = '192.168.1.101'
password = 'pass'
'''
/* -------------------------------------------------------------
* reboot target device and connect to target by ipmitool
* ------------------------------------------------------------- */
'''
os.system('ipmitool -H %s -I lanplus -U root -P %s sol deactivate' % (ip, password))
os.system('ipmitool -H %s -I lanplus -U root -P %s chassis power reset' % (ip, password))
child = pexpect.spawn('ipmitool -H %s -I lanplus -U root -P %s sol activate' % (ip, password))
'''
/* -------------------------------------------------------------
* wait "Press any other key in .* seconds to stop automatical booting", enter to uefi
* ------------------------------------------------------------- */
'''
index = child.expect(['Press any other key in .* seconds to stop automatical booting', pexpect.EOF, pexpect.TIMEOUT])
while (index != 0):
index = child.expect(['Press any other key in .* seconds to stop automatical booting', pexpect.EOF, pexpect.TIMEOUT])
child.sendline("")
'''
/* -------------------------------------------------------------
* enter into Boot Manager
* menu entry: Boot Manager、Device Manager、Boot Maintenance Manager
* ------------------------------------------------------------- */
'''
Boot_Manager = 'Boot Manager'
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m' % (Boot_Manager), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
while (index != 0):
child.sendline("v")
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m' % (Boot_Manager), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
time.sleep(1)
child.sendline('\r\n')
'''
/* -------------------------------------------------------------
* enter to Boot Manager -> EFI Network 2
* ------------------------------------------------------------- */
'''
efinetwork2 = 'EFI Network 2'
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m.*' % (efinetwork2), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
while (index != 0):
child.sendline("v")
index = child.expect(['\\x1b\[0m\\x1b\[37m\\x1b\[40m.*%s\\x1b\[0m\\x1b\[30m\\x1b\[47m.*' % (efinetwork2), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
child.sendline('\r\n')
'''
/* -------------------------------------------------------------
* select and enter to grub entry "Startup Estuary"
* ------------------------------------------------------------- */
'''
startup = 'Startup Estuary'
child.expect('Press .* to edit the selected item')
index = child.expect(['\\x1b\[30m\\x1b\[47m.*%s.*\\x1b\[0m\\x1b\[37m' % (startup), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
while (index != 0):
child.sendline('v')
index = child.expect(['\\x1b\[30m\\x1b\[47m.*%s.*\\x1b\[0m\\x1b\[37m' % (startup), pexpect.EOF, pexpect.TIMEOUT], timeout = 1)
child.sendline('\r\n')
child.interact()