[OutSystems]自動テストツールでFront-endのステータスを取得

たまに、Schedulerサービスが落ちていて、Timerが止まったりするので、監視する方法を考えてみる。
調べた限り、標準で備えられたAPIには、Schedulerなどの死活を確認する方法が無いようなので、自動テストツール（CodeceptJS）を使って、Environment Healthページから取得する方法を検討する。

# 確認環境
Personal Environment(Version 11.14.0 (Build 33133))
Service Studio (Version 11.14.8)

# CodeceptJSとは
オープンソースのE2Eテストツール。
ブラウザを操作して、WebアプリケーションのI/Fを利用したテストを作成できる。
https://codecept.io/

以前、QiitaにCodeceptJSを利用してService Centerを操作する例を投稿しているので、参考までに。
[Service CenterをCodeceptJSで操作してみる](https://qiita.com/jyunji_watanabe/items/b39e40974b5fe17dec82)

# Environment Healthの構造をチェック
Environment HealthはService Centerの１ページで、Monitoring > Environment Healthの順番でヘッダのリンクを踏むと開く。
ページ内にはいくつかの情報が含まれるが、先頭にあるFront-end Serversのテーブル（下の黄色の部分）にSchedulerを始めとするサービスの状況が表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/b4dac350-457f-c0b1-7148-c9ef6f511488.png)

Personal EnvironmentではFront-endは1台なので、決め打ちでlocatorを決めてしまうことにする。
Chromeの開発者ツールを使ってSchedulerのHTML構造を確認してみると、
以下のスクリーンショットの通り

1. 最初のtableタグ（Environment Healthにはtableがいくつかあるが、Front-end Serversのセクションは先頭にあるので）
1. tbodyタグ内の最初のtrタグ（theadタグにもtrがあるのでtbody内とする）
1. n番目のtdタグ内のimgタグ（とりたいサービスによって何番目かが異なる）
1. imgタグのtitle属性

とたどると、欲しい情報（対象サービスの死活）がとれそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/e449a25b-03e0-f1d3-2781-317aefa45d50.png)

# locatorを組み立てる
上で見た構造をCSS locator (CodeceptJSにはlocatorの指定方法が複数あるが、そのうちCSSを使って指定する方法）にすると、

``` js
.table:nth-of-type(1) tbody td:nth-of-type(1) img
```

「:nth-of-type」は指定したタグが同じ位置で複数ヒットする場合に、何番目を取るかを指定するもの。

# CodeceptJSでHTMLの属性を取得する
grab系関数を使う。grabがついているものはasyncの関数なので、呼び出し時にawaitしている。
属性を取得するには、grabAttributeFrom(ロケータ, 属性名)とする。

``` js
await I.grabAttributeFrom('.table:nth-of-type(1) tbody td:nth-of-type(1) img', 'title')
```

# サンプルコード
取得処理だけを実装したサンプル。
## github
https://github.com/jyunji-watanabe/ServiceCenterAutomation

## テストスクリプト
PageObjectを利用して情報を取得し、ターミナルに出力する。
フォーマットは「実行日時,Deployment Controllerのステータス,Schedulerのステータス,...」。
envやmenuについては、[Service CenterをCodeceptJSで操作してみる](https://qiita.com/jyunji_watanabe/items/b39e40974b5fe17dec82)を参照。

``` js
Feature('EnvironmentHealth');
require('dotenv').config({ path: '.env' });
let utility = require('../utilities/utility.js');
Scenario('Retrieve status of Front-end Servers on Personal Environment', async ({ I, environmentHealthPage }) => {
    I.amOnPage('/');
    I.login(process.env.ACCOUNT, process.env.PASSWORD);
    environmentHealthPage.open();
    let value = await environmentHealthPage.getFrontEndStatuses();
    // format the returned value here 
    let result = utility.getDateTimeText() + "," + 
                 value.deployController + "," + value.scheduler + "," + value.deploymentImg + "," +
                 value.iisImg + "," + value.serverAPIImg + "," + value.serverIdentityImg;
    // show result on the terminal. In real projects, we should push this information to a file or DB to check the difference or something.
    I.say(result);
});
```

## PageObject
Front-end Serversの6つのステータスを全て取得する。

``` js
const menu = require('../../utilities/menu');

const { I } = inject();
module.exports = {
    locators: { // these locators are determined by looking at PE. It should be changed if you use this logic on your environment other than PE.
        frontEndTableBody: '.table:nth-of-type(1) tbody',
        deployControllerImg: 'td:nth-of-type(1) img',
        schedulerImg: 'td:nth-of-type(2) img',
        deploymentImg: 'td:nth-of-type(4) img',
        iisImg: 'td:nth-of-type(5) img',
        serverAPIImg: 'td:nth-of-type(6) img',
        serverIdentityImg: 'td:nth-of-type(7) img',
    },
    open: function() {
        menu.open('Monitoring', 'Environment Health');
    },
    async getFrontEndStatuses() {
        // PE offeres only one row for the Front-end Servers section
        let firstRowSelector = this.locators.frontEndTableBody + ' tr:nth-of-type(1) ';
        let value = {
            deployController: await I.grabAttributeFrom(firstRowSelector + this.locators.deployControllerImg,
                                                        'title'),
            scheduler: await I.grabAttributeFrom(firstRowSelector + this.locators.schedulerImg,
                                                        'title'),
            deploymentImg: await I.grabAttributeFrom(firstRowSelector + this.locators.deploymentImg,
                                                        'title'),
            iisImg: await I.grabAttributeFrom(firstRowSelector + this.locators.iisImg,
                                                        'title'),
            serverAPIImg: await I.grabAttributeFrom(firstRowSelector + this.locators.serverAPIImg,
                                                        'title'),
            serverIdentityImg: await I.grabAttributeFrom(firstRowSelector + this.locators.serverIdentityImg,
                                                        'title')
        }
        return value;
    }
}
```

## 実行例
コマンド（ターミナルにsay関数で出力しているので--stepsをつけている）
```
npx codeceptjs run .\tests\environmenthealth_test.js --steps
```

出力例
```
2022/03/19 15:40:32,Ok,Ok,Ok,OK,OK,OK
```

# 注意点
この記事のEnvironment HealthのスクリーンショットはPersonal Environmentなので、Front-end Serverが1行しか表示されず、本来なら表示されるIPアドレスなども表示されていない。
→実用時には、各環境に合わせた調整が必要

ここで示したサンプルはターミナルに出力するだけだが、本来ならファイルかDBに履歴を蓄積し、n回続けてOK以外のステータスであればアラートを出す、という実装にする必要があると思われる。