[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で操作してみる

Environment Healthの構造をチェック

Environment HealthはService Centerの1ページで、Monitoring > Environment Healthの順番でヘッダのリンクを踏むと開く。
ページ内にはいくつかの情報が含まれるが、先頭にあるFront-end Serversのテーブル(下の黄色の部分)にSchedulerを始めとするサービスの状況が表示される。

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

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

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

locatorを組み立てる

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

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

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

CodeceptJSでHTMLの属性を取得する

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

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

サンプルコード

取得処理だけを実装したサンプル。

github

テストスクリプト

PageObjectを利用して情報を取得し、ターミナルに出力する。
フォーマットは「実行日時,Deployment Controllerのステータス,Schedulerのステータス,...」。
envやmenuについては、Service CenterをCodeceptJSで操作してみるを参照。

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つのステータスを全て取得する。

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以外のステータスであればアラートを出す、という実装にする必要があると思われる。