はじめに
ビジネス駆動、駆動しなければ動かない
一.背景
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
メール通知セクションの下部にテストメールを送信して設定をテストオプションがあります。受信者を入力してテスト送信し、受信できれば OK です
P.S.システム管理者メールアドレスの入力に特别注意してください。さもないと永遠に送信できません(送信者が未設定)
次に「Extended E-mail Notification」を設定します。ビルド後のメール通知の内容はここで設定します。例えば:
Extended E-mail Notification
---
SMTP サーバー smtp.163.com
デフォルトの Content Type HTML(text/html)
SMTP 認証を使用
ユーザー名 xxx
パスワード ***
下部の「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
するとメールが 1 通届きます:
件名: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 フィールドを読み取ることを許可し、有効期限を 3600 秒(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 は多くの詳細な作業を処理してくれ、このようなビルドサービスを手動で実装するよりも便利ですが、設定可能な項目が多いほど制御権は低くなり、簡単な操作を完了するためにもプラグインに頼るか、迂回した方法を使用せざるを得なくなります
いずれにせよ、自動的にテストケースを実行し、インフラストラクチャの安定性を保証するのは非常に良いことです。始めましょう
コメントはまだありません