Python3 pexpect自動化測試

Python3 pexpect自動化測試

1. pexpect簡介

1.1 pexpect超時異常/程序結束

    不將pexpect.EOF、pexpect.TIMEOUT加入pexpect列表時,在程序運行結束或者pexpect超時的情況下,將拋出異常,可以使用"try ... except ..."來捕獲處理異常,但是這改變了程序的正常執行流程,因此建議在使用pexpect的時候將pexpect.EOF、pexpect.TIMEOUT加入pexpect列表,使程序的執行流程可控,同時也可以直接使用pexpect的返回值做相應的處理。

1.2 pexpect timeout參數設置

    pexpect等待程序timeout應根據命令實際執行時間來確定,以避免不必要的等待時間;例如,某條命令執行僅需1秒,則可設置timeout = 3,給程序足夠的執行時間,又能避免不必要的等待。

2. AARCH64服務器reboot

2.1 reboot過程介紹

    AARCH64服務器reboot之後將從固化在單板Flash存儲器中的UEFI啓動,由UEFI來引導grub內核啓動,再由grub引導linux內核啓動;
如下圖所示,UEFI將提示用戶“Press Enter to boot OS immediately.”、“Press any other key in 10 seconds to stop automatical booting...”。


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()




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章