Seleniumの実行を自動化したはなし 

### はじめに

[ラクス Advent Calendar 2020](https://qiita.com/advent-calendar/2020/rakus)16日目の記事です。

この記事の内容はどこかのタイミングで書こうと思いつつも、なんとなく機会を逃していたものです。初アドベントカレンダー参加の機会に書きました。

この記事の内容をざっくりまとめると...

* ローカルPC -> Server の `Seleniumの実行`を自動化した話
    * [弊社のMeetupにて過去発表のあった、重要機能Seleniumテスト](https://speakerdeck.com/mickeystrange/ririsu10zhou-nian-woying-etawebdbsisutemufalsepin-zhi-dan-bao-shu?slide=20)のこと
* Seleniumによる自動テストは作成されているけど、実行が手動で実施コストが大きかった
* 最終的に Jenkins から実行できるようにした

### 自動化対応前の状態

下図が実行時の構成イメージです。

![Untitled Diagram-Page-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675806/dcc379a6-0476-7801-ced6-8a16fdd659e6.png)


1. 事前準備
    1. バッチ処理を止める
    1. アプリケーションのソース最新化（ブランチ切り替え）
    1. ベースのdumpを展開
1. Selenium実行
1. diff取得
    1. 止めていたバッチ処理を実行
    1. 前回実行時のdumpを展開
    1. DBのデータからdiffを取得
1. diffを目視チェック

### めんどくさいポイント

手動で実行する際にめんどくさいポイントがいくつかありました。

#### Seleniumの実行が不安定

リトライ処理も入れていたものの、要素が取得できずにコケてSeleniumが終了することが多発していました。その都度うまく動いた操作・テストケースをコメントアウトして再実行していたため、非常に面倒でした。
コメントアウトして再実行というノウハウの存在自体がBadだと思います。

またコケていた原因は深く追求していませんが、ローカルPCかつnotヘッドレスで実行したことが影響していそうだと推測しています。具体的には、別作業をしてウィンドウが非アクティブになったときにうまく要素が取得できなかったのでは？ と考えています。

#### スクリプトの実行が面倒

dumpの展開やバッチ処理の実行など、それぞれスクリプト化されており実行するだけの状態にはなっていました。しかし1本にまとまっていたわけではなく、それぞれ実行する必要があり微妙に面倒でした。特にバッチ処理が完了するまで10分程度かかったので、その微妙な待ち時間がツラかった。。

上記の不安定さと相まって、お守りが必要なので気軽に実行できる状態ではありませんでした。

#### diffチェックが目視

具体的には新旧それぞれのDBのデータをCSVとして出力し、それらに対するdiffコマンドの実行結果を目視で確認していました。
[Man page](https://linuxjm.osdn.jp/html/gnumaniak/man1/diff.1.html)で確認すると以下の通り、差分がないことときは返り値から判断できるので、差分がないことの多い通常ケースでは目視で確認する必要がありませんでした。

> 返り値
> **diff** は以下の値のどれかで終了する:
> **0**
> 　全く変更がなかった。

### 自動化ポイント

上記のようなめんどくさいポイントを解消するために自動化しました。下図はその時の構成イメージです。

![Untitled Diagram-Page-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675806/cbc13c40-73cd-b246-bf5b-bc202df17495.png)

* 事前準備〜diffチェックまでをスクリプト1本にまとめる
* まとめたスクリプトをJenkinsから実行できるようにする
    * GUIでポチポチできると非常に楽になる
* 実行結果をチャットで通知
    * 終了時間を見計らって結果をキャッチアップしにいくのはやりたくない

### 苦労したポイント

#### CentOS6 に Chrome が入らない

自動化するにあたり、Seleniumを動かすサーバを新しく用意する必要がありました。
当時アプリケーションが動いていたサーバはCentOS6で動いていたので、そのまま転用できるかと考えていたものの、ChromeがCentOS6にはインストールできないことが判明し断念しました。
CentOS7ではインストールできるとの情報があり、構築するコストも低かったのでCentOS7で動かすことに決定しました。

#### オフライン環境のツラミ

上記の専用に用意したサーバがグローバルのインターネットにアクセスできない環境に構築したため、Chromeなどの諸々が直接インストールできない状態に（事前の想定が不足していた。。）。
最低限ローカルPCからアクセスできる状態ではあったので、ローカルで必要データを準備・転送してインストールすることに。

##### Chrome のインストール

VirtualBox上のCentOS7でrpmを作成し、それを転送してインストールしました。
当時参考にしていたサイトとは違いますが、おおよそ以下の記事ようなことを実施した記憶があります。

* https://qiita.com/yokra9/items/e8842dee2c42fc479931

##### Mavenのビルド

ライブラリをダウンロードできず、当然ビルドもできないので、以下のような対応に。

* ライブラリはローカルで動かしたときの`.m2`ディレクトリをまるまる転送
* コンパイル・実行は`javac`・`java`コマンドで実施

ローカルでビルドしたjarを配置することも考えましたが、Seleniumコードの修正／拡張に追従するのに手作業が必要となってしまうのでボツにしました。

#### 実行が異常に遅い

いざ実行準備が整ったので実行してみると、異常なくらい遅く、全く使い物にならない状態でした。CPUやメモリはほぼ使っておらず、なかなか原因がつかめなかったのですが、全ての画面表示時にGoogleアナリティクスのリクエストがタイムアウトするまで待っていたことが原因でした。
このときは思い至らなかったのですが、Chromeのコンソールエラーなどを捕捉する手段がわかっていればもっと早く原因に気付けたかもしれません。

そもそもアナリティクスを動かす意味がないので、スクリプト部分をバッサリ削除して対応しました。

### 自動化の効果

JenkinsのGUIをポチポチして実行した後はチャットに通知が来るのを待つだけなので、実行中にお守りする必要がなくなりました。その間別作業に集中することができます。
また、この後Jenkinsのプラグインを利用して定期実行に対応しました。自動化の対応前ではリリースバージョンごとに1回の実行頻度だったのが、これで毎日実行されるようになりました。デグレ発見タイミングが早くなることが期待できそうです。


### 参考

* https://speakerdeck.com/mickeystrange/ririsu10zhou-nian-woying-etawebdbsisutemufalsepin-zhi-dan-bao-shu
* https://linuxjm.osdn.jp/html/gnumaniak/man1/diff.1.html
* https://qiita.com/yokra9/items/e8842dee2c42fc479931
* https://www.jenkins.io/artwork/
* https://handbook.mattermost.com/operations/operations/company-processes/publishing/publishing-guidelines/brand-and-visual-design-guidelines