HTTP觸發Jenkins參數化構建(CORS Plugin)

https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

寫在前面

業務驅動,不驅就不動

一.背景

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
---
系統管理員郵件地址  [email protected]

郵件通知部分底部有通過發送測試郵件測試配置選項,填寫收件人試一發,能收到就好

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    [email protected]
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: [email protected]
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搞定了很多細節的工作,比手動實現這樣一套構建服務要方便一些,但可配置度越高,控制權就越低,想要完成一些簡單的操作,不得不求助於插件或者通過一些繞來繞去的方式

不管怎樣,自動跑用例,保證基礎設施穩定性是極好的,搞起來

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