寫在前面
業務驅動,不驅就不動
一。背景
用 Selenium 來做前端自動化測試,希望一提代碼就來份測試報告:
1.push/merge 遠程代碼
2. 自動跑測試用例
3. 郵件通知測試結果
由 Webhook 來連接 Git 操作和構建過程,這樣每次 push/merge 等 Git 操作時,Webhook 就會(請求)通知構建服務,然後執行整個構建過程,構建完畢後郵件通知
本來 Jenkins 已經提供一條龍服務了,簡單配置一下就好。Webhook 觸發 Jenkins job,同步構建完畢後發郵件出來
但由於前端環境的特殊性(測試用例要在瀏覽器環境跑),而測試結果也在 JS 手裡,於是就有了異步跑完用例後怎麼通知 Jenkins的問題
用 Selenium 起一個瀏覽器,訪問測試頁面,等所有 case 執行完畢(包括異步 case),這時才拿到測試結果。而構建腳本可能在瀏覽器還沒打開的時候就執行完畢了,準備發郵件用例還沒跑完
所以先把發郵件的任務拆出來,作為獨立的 job,專門負責發郵件。那麼只缺少 JS 通知 Jenkins 發郵件這一環了
二。專門發郵件的 job
配置 SMTP
在「Jenkins/系統管理/系統設置」裡填寫 SMTP 相關配置,以及系統管理員郵件地址,例如:
郵件通知
---
SMTP 服務器 smtp.163.com
使用 SMTP 認證
用戶名 xxx
密碼 ***
Jenkins Location
---
系統管理員郵件地址 user @163.com
郵件通知部分底部有 通過發送測試郵件測試配置 選項,填寫收件人試一發,能收到就好
P.S. 特別注意填寫系統管理員郵件地址,否則永遠發不出去(沒填發件人)
然後配置「Extended E-mail Notification」,構建後郵件通知的內容在這裡設置,例如:
Extended E-mail Notification
---
SMTP server smtp.163.com
Default Content Type HTML(text/html)
Use SMTP Authentication
User Name xxx
Password ***
勾選底部「Enable Debug Mode」方便排查郵件發送失敗原因
參數化構建
在「General/參數化構建過程」裡設置參數名、預設值及描述,例如:
String Parameter
---
名字 autoTestResult
預設值 自動測試失敗
描述 自動測試結果,不通過的用例有哪些
在「構建觸發器/觸發遠程構建 (例如,使用腳本)」裡填寫 token,作為構建口令,例如:
身份驗證令牌 mail
在「構建」裡執行 shell(用來測試參數傳遞):
echo $autoTestResult
echo 'hoho, the end'
在「構建後操作」裡添加「Editable Email Notification」,填寫收件人/內容等項,例如:
Project Recipient List user @163.com
Default Subject autoTest 通知
Default Content $autoTestResult
然後在「Advanced Settings/Triggers」裡添加「Always」,預設只在構建失敗時發郵件,改為無腦發
然後嘗試一下,手動觸發(瀏覽器訪問):
http://localhost:2017/job/mail/buildWithParameters?token=mail&cause=shoujian&autoTestResult=allpassed
一切正常的話,本次構建的「Console Output」面板會出現如下 log:
Started by remote host 0:0:0:0:0:0:0:1 with note: shoujian
Building in workspace /Users/Shared/Jenkins/Home/jobs/mail/workspace
Checking for pre-build
Executing pre-build step
Checking if email needs to be generated
No emails were triggered.
[workspace] $ /bin/sh -xe /Users/Shared/Jenkins/tmp/hudson5065606977113971836.sh
+ echo allpassed
allpassed
+ echo hoho
hoho
Checking for post-build
Performing post-build step
Checking if email needs to be generated
Email was triggered for: Always
Sending email for trigger: Always
messageContentType = text/html; charset=UTF-8
Collecting change authors...
build: 17
Adding recipients from project recipient list
Adding recipients from trigger recipient list
Successfully created MimeMessage
Sending email to: user @163.com
Finished: SUCCESS
然後將收到一封郵件:
主題:autoTest 通知
內容:allpassed
P.S. 如果按照上面的步驟一點一點來,應該一切正常,如果報錯或者收不到郵件,請查看 Jenkins Email sending fails
三.HTTP 觸發 Jenkins 郵件 job
由 JS 發 HTTP 請求觸發 Jenkins 任務,會遇到 3 個問題:
-
CSRF 保護
-
CORS
-
登錄驗證(Basic Auth)
預設有跨站請求頭偽造保護和跨域限制,而且要求登錄(但支持 Basic Auth)
如果經服務中轉,這些都不是問題,拿到 crumb 通過 CSRF,無腦跨域,header 驗證。但考慮構建工具只在測試環境跑,沒必要這麼繞,乾脆關掉 CSRF 保護,開啟 CORS 白名單,最後 JS 可以通過XHR 設置 header 完成 Basic Auth 登錄
關掉 CSRF 保護
在「Jenkins/管理 Jenkins/Configure Global Security」裡不勾選防止跨網站請求偽造
這樣就不用取 crumb 驗證了,測試環境,風險不大
開啟 CORS 白名單
有一個 CORS 插件,專門幹這個事情:CORS support for Jenkins
在「Jenkins/系統管理/系統設置/CORS Filter」裡填寫跨域限制相關響應頭,例如:
Is Enabled
Access-Control-Allow-Origins http://localhost:3000
Access-Control-Allow-Methods POST
Access-Control-Allow-Headers Authorization
Access-Control-Max-Age 3600
P.S. 如果值有多個,用 , 隔開,例如 POST,GET
把 POST http://localhost:3000 添進白名單,允許 XHR 讀取響應頭的 Authorization 字段,身份證有效期為 3600s(1 小時)
P.S. 關於 CORS 的更多信息,請查看 跨域資源共享 CORS 詳解
XHR 登錄
new Image() 最方便,但沒辦法進行 Basic Auth。XHR GET 也可以,但 URL 長度限制總不爽,所以選擇 XHR POST,示例如下:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if((xhr.status >=200 && xhr.status < 300 ) || xhr.status == 304 ){
console.info('jenkins 觸發成功');
} else {
console.info('jenkins 觸發失敗 ' + xhr.status + '\n' + xhr.responseText);
}
}
};
var result = 'allpassed';
var url = 'http://localhost:2017/job/mail/buildWithParameters?token=mail&cause=shoujian&autoTestResult=' + result;
xhr.open('POST', url, true);
// Basic Auth
var username = 'jenkins', password = '2017';
xhr.setRequestHeader('Authorization', 'Basic ' + btoa(username + ':' + password));
xhr.send(null);
測試用例全部執行完畢後,把測試結果 POST 出去,通知 Jenkins 發郵件。到這裡前端自動化測試就能跑起來了
P.S. 關於 XHR Basic Auth 的更多信息,請查看 Jenkins json REST api with CORS request using jQuery
PHP 觸發 Jenkins 參數化構建
如果考慮安全風險,或者希望在跑完測試用例後做更多的事情,可以由服務觸發構建,PHP 代碼如下:
header('Access-Control-Allow-Origin:*');
// 觸發構建
// exec("curl -X GET \"http://127.0.0.1:2017/job/mail/build?token=mail&cause=nocause\" --user user:passwd", $res, $rt);
// 參數化構建
exec("curl -X GET \"http://127.0.0.1:2017/job/mail/buildWithParameters?token=mail&cause=nocause&autoTestResult=allpassed\" --user user:passwd", $res, $rt);
if ($rt !== 0) {
echo '出錯了<br>';
var_dump($res);
}
else {
echo 'ok';
}
exec 調用 curl 發送 GET 請求,POST 方式與之類似,不再贅述
P.S. 關於遠程觸發構建的更多信息,請查看官方文檔:Remote access API
四。寫在最後
Jenkins 搞定了很多細節的工作,比手動實現這樣一套構建服務要方便一些,但可配置度越高,控制權就越低,想要完成一些簡單的操作,不得不求助於插件或者通過一些繞來繞去的方式
不管怎样,自動跑用例,保證基礎設施穩定性是極好的,搞起來
暫無評論,快來發表你的看法吧