Python3 pexpect自動化測試
1. pexpect簡介
1.1 pexpect超時異常/程序結束
1.2 pexpect timeout參數設置
2. AARCH64服務器reboot
2.1 reboot過程介紹
2.2 Python腳本分析
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("")
3. 進入uefi手動設置界面
3.1 uefi設置界面如下
3.2 思路分析
此界面菜單順序基本是固定的,可以通過按指定次數方向鍵高亮目標菜單,然而這種做法寫出的腳本在不瞭解背景的情況下,沒法看懂腳本用意,其次擴展性、可維護性不好,萬一菜單有所增減或順序調整,則腳本必須隨之修改;
我們是通過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 "..."解析控制字符串,查看執行結果,獲取菜單高亮對應的字符串(去掉不必要的座標轉義字符)。
3.3 python腳本
(高亮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')
4. 啓動設備選擇
4.1 啓動設備菜單界面
4.2 思路分析
菜單選擇與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)
4.3 EFI Network 2腳本示例
#!/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')
5. 進入grub
5.1 grub界面
5.2 grub菜單選擇界面腳本
(獲取菜單高亮控制字符串等請參考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')
6. 啓動linux
7. 完整Python腳本示例
#!/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()