ついにこの時が来ました、、
「Gitプッシュすれば勝手にSeleniumの自動テストが夜中に走り、朝テスト結果を確認する」という夢が叶うときが・・・!
Jenkins+Git+Seleniumによりなんとか形になりました。
個人的には結構大変でした、、ぜひ何かの足しになればと思います。
※備忘録的な意味も強い、忘れてしまいそう。。。
目次
全体像
上記が全体の構成イメージとなります。
サーバ群概要
検証には全てミラクルリナックス8.8で構成しています。
※特にこだわりはありません
Jenkinsサーバ(192.168.0.11)
Jenkinsをインストールしたサーバです。
Githubの監視を行い、必要に応じてAPサーバ、Seleniumサーバにコマンドを送ります。
APサーバ(192.168.0.6)
開発中システムのテストサーバです。
今回はメールフォームを開発中という例で検証していきます。
ちなみにフォームは下記のような感じです。
Seleniumサーバ(192.168.0.10)
Python+Seleniumがインストールされているサーバです。
下記の記事にある手順で構築された環境です。
フローの概要
①ソースのプッシュ
プログラマー等がGit上にファイルをプッシュします。これをトリガーとして自動テストを実行していきます。
②SCMポーリングによる更新のチェック
③更新があったらソースの取得
JenkinsはGit上のソースが更新されたかを常にチェックさせるようにします。
もし更新が確認ができたら、ソースをダウンロードし、APサーバ(テスト対象)のファイル更新・リセットと、Seleniumサーバにテストの実行を命令します。
ポーリング周りは下記の記事と同じように設定しています。
④ファイル更新、リセット
JenkinsがGitからダウンロードしたファイルをAPサーバにアップし、環境情報のリセットを行います。
リセットとは、前回のテストの残骸を掃除したりなどし、テストに支障が出ないよう一定の環境に差し戻すことを指します。
スナップショットを戻すとかリストアなどの表現が近いかもしれません。
⑤Seleniumのテストを命令
最後にテストを実施するためにSeleniumサーバにPython+Seleniumの実行命令を送ります。
設定のミソ
Jenkinsサーバ、APサーバ、Seleniumサーバが連携する必要があり、ここがインフラ初級者にとっては若干苦痛で、セキュリティを考慮すると諸々大変なのですが、そういった点は主題ではないので今回は無視し、
通信はすべてrootユーザ
で実行します。
APサーバ(テスト対象)の設定
ディレクトリ構造
/var/www/html/ ※公開ディレクトリ
┗form_check ※メールフォームディレクトリ
┗index.php
┗confirm.php
┗thanks.php
┗data.tsv
┗common.css
公開ディレクトリはapache標準の「/var/www/html」にします。
今回テスト対象となるシステムは直下の「form_check」ディレクトリで構成・完結しています。
これらをGithubのファイルで更新し、Seleniumでテストをしていきます。
Jenkins用の受付ディレクトリを作成
#Jenkinsの通信を受け付けるディレクトリを専用に作成(root操作)
mkdir /var/www/jenkins
mkdir /var/www/jenkins/source
jenkinsディレクトリを作成し、その下にJenkinsから受け取るコマンド、ソース群を配備します。
セットアップ用バッチの作成
次にAPサーバの環境をセットアップするバッチを作成します。
このバッチはSeleniumでテストが可能な状態にリセットするためのコマンド群を記述します。
vi /var/www/jenkins/setup.sh
#Githubのファイルを反映
cp -r /var/www/jenkins/source /var/www/html/
#必要なパーミッションの割り当て
chown -R apache:apache /var/www/html/
#念のためsourceディレクトリは別ディレクトリ名で残し、次のセットアップ用にsourceディレクトリを再作成
mv /var/www/jenkins/source /var/www/jenkins/source`date +%Y%m%d%H%M%S`
mkdir /var/www/jenkins/source
今回は単純なメールフォームなので、公開ディレクトリ(/var/www/html)以下のファイルを上書きしているのみになりますが、DBを使うならダンプファイルからリストアするなどコマンドを加えます。
またファイルアップロードやテスト環境の実データの状態をリセットしたい場合も、このバッチに記載しておきます、どのような状態にリセットするかはGithub側にテストデータを格納しておき、それを展開するでもいいのかなと思います。
chmod 755 /var/www/jenkins/setup.sh
忘れずに実行権限を与えておきます。
Seleniumサーバの設定
ディレクトリ構造
/root/
┗sample.py ※Selenium実行
┗seleniumlog ※Seleniumが実行されたかを確認するログ置き場
┗YYYYMMDDHHiiss.log
┗YYYYMMDDHHiiss.log
┗YYYYMMDDHHiiss.log ...
(考えるのがめんどうだったので、、、)root直下にsample.pyを置き、実行ログをseleniumlogディレクトリに書き出すようにします。
vi /root/sample.py
from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options
import datetime
f = open("/root/seleniumlog/"+datetime.datetime.now().strftime("%Y%m%d%H%i%s")+".log","a",encoding="UTF-8")
f.write("Selenium Start\t:"+datetime.datetime.now().strftime("%Y%m%d%H%i%s")+"\n")
options = Options();
options.add_argument('--no-sandbox')
#options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get("http://192.168.0.6/form_check")
f.write("Page Title\t:"+driver.title+"\n")
sleep(1)
driver.quit()
動けばいいので中身はなんでもいいのですが、APサーバのメールフォームである「http://192.168.0.6/form_check」にアクセスし、ページタイトルをログに書き出すようにします。
実際にテストをするなら、ここでテスト入力をして結果を整形して書き出すことになると思います。
動いているかどうかよくわからないときは「#options.add_argument('--headless')」のコメントアウトを外し、正しく動いているか確認します。
Jenkinsサーバの設定
テスト対象サーバー用の鍵を作成
#鍵の作成 ※パスフレーズなし
ssh-keygen -t rsa -b 4096
#作成した公開鍵をAPサーバーに送信
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.0.6
#Jenkinsサーバー内で秘密鍵の置き場所を整理 ※ちょっと雑かも
chown jenkins:jenkins /root/.ssh/id_rsa
mkdir /var/lib/jenkins/ssh/
mv /root/.ssh/id_rsa /var/lib/jenkins/ssh/id_rsa
SSH接続をするためにテスト対象サーバーに渡す鍵情報を作成します。
作成した公開鍵は「ssh-copy-id」コマンドで送信します。
秘密鍵はJenkins側で参照してssh通信をするので、適当な場所に配備しておきます。
鍵が正常に配備できたかどうかは、テスト対象サーバーの「/root/.ssh/authorized_keys」が作成されているor現在時刻で更新されていればOK。
Seleniumサーバー用の鍵を作成
#鍵の作成 ※パスフレーズなし
ssh-keygen -t rsa -b 4096
#作成した公開鍵をAPサーバーに送信
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.0.10
#Jenkinsサーバー内で秘密鍵の置き場所を整理
chown jenkins:jenkins /root/.ssh/id_rsa
mv /root/.ssh/id_rsa /var/lib/jenkins/ssh/id_rsa_selenium
Seleniumサーバーにも接続するので同じように鍵を作成します。
流れは同じですが鍵の名前がJenkinsサーバー内で重複しないよう最後にリネームしておきます。
ビルドの設定
scp -r -i /var/lib/jenkins/ssh//id_rsa $WORKSPACE/form_check root@192.168.0.6:/var/www/jenkins/source
ssh -i /var/lib/jenkins/ssh/id_rsa root@192.168.0.6 /var/www/jenkins/setup.sh
nohup ssh -i /var/lib/jenkins/ssh/id_rsa_selenium root@192.168.0.10 /usr/bin/python3 /root/sample.py &
ビルド時に実行するコマンドは3点です。
- Githubから取得したソースをテスト対象サーバーに送信
- テスト対象サーバーのsetup.shを実行し、環境をリセット
- Seleniumサーバーに実行命令を送信
$WORKSPACE変数を使うことで、Jenkinsの当該ジョブディレクトリのパスが取得できます。そこから必要なディレクトリ、ファイルを指定してAPサーバ側にscpでコピーを送ります。
コピー後、setup.shで環境をリセットします。
最後だけバックグラウンド実行にしているのは、Seleniumが長時間動く場合に不安定になる可能性があるのと、テスト結果をJenkinsで受け取るわけではないので、それを待つ必要はないと思ったからです。
まとめ
これで本当にいいのだろうか、、
という気は若干残る構成なのですが、Jenkins初心者の取っ掛かりとしてはそこまで悪くはないのではと思いました。
各所rootで実行していたり、テスト終了を検知できていなかったりと、改善点は多々ありそうですが、当初Seleniumでやりたかったことはやれたかなと感じています。
Seleniumをちゃんと勉強し始めてからどれぐらいたったろう、、、仕事で手が付けられない時期もありましたが、3年ぐらい経っていて時間の流れが矢はいことを実感します。
今後Seleniumの備忘録として細かい部分の記事になるかも、、
あとは実務でどう活かすか、こっちはどうしようかと本気で悩んでいます。。。