2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NeuStar VirtualUser Script 覚書

Last updated at Posted at 2018-03-04

米国の Neustar 社が提供しているサービスの一つで、Webサイトに対する負荷試験が行える。

以下、VirtualUserでの試験実行でよく使うサンプルなど。

基本(GET)

単発でGET実行。POST等の他メソッドも概ね同じように利用可能。

var c = test.openHttpClient();

// Set Parameters
c.setCheckValidSSL(false);
c.setConnectionTimeout(30000);
c.setDNSCacheTimeout(0);
c.setEnableSNI(true);
c.setFollowRedirects(true);
c.setRequestTimeout(60000);
c.setRetryCount(0);
c.setSocketOperationTimeout(30000);
// Set Parameters

test.beginTransaction();
test.beginStep("Check Website");

c.get("https://google.com/");

test.endStep();
test.endTransaction();

HttpClient 設定変更

HttpClientに設定可能な値

| Class | AllowValues | Deafult | Note |
| --- | --- | --- | --- | --- |
| setCheckValidSSL | boolean | false | SSL証明書検証 |
| setConnectionTimeout | int | 30000 | 接続タイムアウト、単位:ミリ秒 |
| setDNSCacheTimeout | int | ? | DNSキャッシュTTL、-1は永久、0は無効 |
| setEnableSNI | boolean | true | SNI有効化、'handshake alert: unrecognized_name:'が返される場合は false を指定 |
| setFollowRedirects | boolearn | true | リダイレクト追跡 |
| setRequestTimeout | int | -1 | リクエスト全体のタイムアウト(リトライも含む) |
| setRetryCount | int | 0 | リトライ回数 |
| setSocketOperationTimeout | int | 30000 | ソケットタイムアウト、単位:ミリ秒 |

  • set〜Timeout を全て -1(無効) にすると永続化される
    • Operation timed out が別に設定おり、75秒程で切断は発生する模様

レスポンスのチェック

返却されるステータスコードの検証

  • リダイレクトは無効化する必要がある
var c = test.openHttpClient();
test.beginTransaction();
test.beginStep("Check Website");

c.setFollowRedirects(false);
c.get("http://google.com/xxx",302);
c.get("https://www.google.co.jp/",200);

test.endStep();
test.endTransaction();

Statusコードが異なる場合は失敗の扱いとなり、後続処理は行われない

Error Message: Expected status code of 302 but saw 404

レスポンス情報取得

レスポンスから各種情報を取得する

var c = test.openHttpClient();
test.beginTransaction();
test.beginStep("Check Website");

c.setFollowRedirects(false);
var res = c.get("https://www.google.co.jp/",200);
var info = res.getInfo();
test.log('Info BlockedTime = ' + info.getBlockedTime());
test.log('Info Browser = ' + info.getBrowser());
test.log('Info ConnectTime = ' + info.getConnectTime());
test.log('Info DnsLookupTime = ' + info.getDnsLookupTime());
test.log('Info End = ' + info.getEnd());
test.log('Info ErrorMessage = ' + info.getErrorMessage());
test.log('Info Host = ' + info.getHost());
test.log('Info Method = ' + info.getMethod());
test.log('Info Path = ' + info.getPath());
test.log('Info PostBody = ' + info.getPostBody());
test.log('Info PostParams = ' + info.getPostParams());
test.log('Info Protocol = ' + info.getProtocol());
test.log('Info QueryString = ' + info.getQueryString());
test.log('Info ReasonPhrase = ' + info.getReasonPhrase());
test.log('Info ReceiveTime = ' + info.getReceiveTime());
test.log('Info RedirectUrl = ' + info.getRedirectUrl());
test.log('Info RequestHeaders = ' + info.getRequestHeaders());
test.log('Info ResolvedIpAddress = ' + info.getResolvedIpAddress());
test.log('Info ResponseHeaders = ' + info.getResponseHeaders());
test.log('Info SendTime = ' + info.getSendTime());
test.log('Info SslHandshakeTime = ' + info.getSslHandshakeTime());
test.log('Info Start = ' + info.getStart());
test.log('Info StatusCode = ' + info.getStatusCode());
test.log('Info TimeActive = ' + info.getTimeActive());
test.log('Info TimeToFirstByte = ' + info.getTimeToFirstByte());
test.log('Info Url = ' + info.getUrl());
test.log('Info WebSocketMessages = ' + info.getWebSocketMessages());
test.log('Body = ' + res.getBody());
test.log('CharSet = ' + res.getCharSet());
test.log('ContentType = ' + res.getContentType());
test.log('ErrorMessage = ' + res.getErrorMessage());
test.log('Url = ' + res.getUrl());
test.log('StatusCode = ' + res.getStatusCode());
test.log('StatusText = ' + res.getStatusText());
res.getAllHeaders().forEach(function(header){
  test.log('Header = ' + header.name + " : " + header.value);
});

test.endStep();
test.endTransaction();
  • 取得例
=====================================================
Script Log
=====================================================
Info BlockedTime = 0
Info Browser = null
Info ConnectTime = 0
Info DnsLookupTime = 2016
Info End = Sun Feb 25 19:46:37 JST 2018
Info ErrorMessage = null
Info Host = www.google.co.jp
Info Method = GET
Info Path = /
Info PostBody = null
Info PostParams = {}
Info Protocol = https
Info QueryString = null
Info ReasonPhrase = OK
Info ReceiveTime = 580
Info RedirectUrl = null
Info RequestHeaders = {User-Agent=[Ljava.lang.String;@6fe643b9, Connection=[Ljava.lang.String;@25a1d233, Host=[Ljava.lang.String;@43afa9bc, Accept-Encoding=[Ljava.lang.String;@5494c28b}
Info ResolvedIpAddress = 172.217.26.35
Info ResponseHeaders = {X-Frame-Options=[Ljava.lang.String;@932a82b, Transfer-Encoding=[Ljava.lang.String;@2229c374, Cache-Control=[Ljava.lang.String;@1cf57cc4, Server=[Ljava.lang.String;@6e07754b, Alt-Svc=[Ljava.lang.String;@7268eb50, Content-Encoding=[Ljava.lang.String;@1eb6a40a, Set-Cookie=[Ljava.lang.String;@2992e844, Expires=[Ljava.lang.String;@7cea6d10, P3P=[Ljava.lang.String;@496d2bb6, X-XSS-Protection=[Ljava.lang.String;@62504065, Date=[Ljava.lang.String;@5c3e44a3, Content-Type=[Ljava.lang.String;@731320d9}
Info SendTime = 3
Info SslHandshakeTime = 0
Info Start = Sun Feb 25 19:46:34 JST 2018
Info StatusCode = 200
Info TimeActive = 2711
Info TimeToFirstByte = 112
Info Url = https://www.google.co.jp/
Info WebSocketMessages = []
Body = <!doctype html>
・・・略
</html>
CharSet = Shift_JIS
ContentType = text/html; charset=Shift_JIS
ErrorMessage = null
Url = https://www.google.co.jp/
StatusCode = 200
StatusText = OK
Header = Date : Sun, 25 Feb 2018 10:46:22 GMT
Header = Expires : -1
・・・略
Header = Transfer-Encoding : chunked

Cookie 取得

ログイン情報をPOSTし、Cookieを取得、使用する例

var c = test.openHttpClient();
test.beginTransaction();
test.beginStep("Check Website");

var req = c.newPost("https://test.example.com/login.html");
req.addRequestParameters({
  'username': 'hoge',
  'password': 'fuga',
});
res = req.execute();
cookie = res.getHeader('Set-Cookie');
test.log('cookie : ' + cookie);

var req = c.newGet("https://test.example.com/");
req.addRequestHeaders({
'Cookie': cookie,
});
var res = web.execute(req);

test.endStep();
test.endTransaction();

HttpClient 動作変更

remapHost

ドメイン名を置き換える。 /etc/hosts のような使い方が可能。

var c = test.openHttpClient();
c.remapHost(sourceDomain, domain);

BASIC認証

var domain = "test.example.com";
var user = "hoge";
var pass = "fuga";

c.autoBasicAuthorization(domain, user, pass);

UserAgent 書き換え

規程のUserAgent "WPM HttpClient/1.0" を任意の文字列に書き換える。

var c = test.openHttpClient();
c.addRequestInterceptor(function(req) {
	req.removeHeaders("User-Agent");
	req.addHeader("User-Agent", "iPhone; WPM HttpClient/1.0");
});

応用(GET)

  • WebBot
    • HTMLを解析し、ページ内リンクに沿ってダウンロードを実施する
  • HttpClient.newGet
    • リクエスト実行前にGET処理を書き換える

ページ内リンクダウンロード

HTMLを解析し、リンクを追従。
Javascript、CSSは解析対象外。
JMeterで言う所の HTTPリクエストの繰り返しダウンロードする

解析・ダウンロード無し

var c = test.openHttpClient();

test.beginTransaction();
test.beginStep("Check Website");

var req = c.newGet("https://www.google.co.jp/");
req.execute();

test.endStep();
test.endTransaction();
  • 指定URLのみが対象
Total Objects: 1

	12143b	200	1466ms	https://www.google.co.jp/

解析・ダウンロード有り

var c = test.openHttpClient();
var web = require('webbot');

test.beginTransaction();
test.beginStep("Check Website");

var req = c.newGet("https://www.google.co.jp/");
var res = web.execute(req);

test.endStep();
test.endTransaction();
  • HTML内のURLまで対象となる
Total Objects: 2

	12635b	200	846ms	https://www.google.co.jp/
	22151b	200	134ms	https://www.google.co.jp/logos/doodles/2018/girls-day-2018-5202534598705152.2-l.png

特定のドメイン・URLを無視する

  • 通常(リスト無し)の場合の返却値
	492231b	200	1533ms	https://www.youtube.com/
	5878b	200	47ms	https://www.youtube.com/yts/jsbin/scheduler-vfl3G47Co/scheduler.js
	・・・
	13661b	200	485ms	https://i.ytimg.com/vi/7glUp6bDU-k/hqdefault.jpg?sqp=-oaymwEWCMQBEG5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLBTAJOcDbo4HIbx4ZfiuRgdqx8Reg
	・・・
	2353b	200	289ms	https://yt3.ggpht.com/ES6oTwtm9iPPjKbkLSbFLpaRdbRObia30kmFKZdcCP1gBasaKEdyVYxrz6zkBC36m-_eYI3pRleRoMEMR3k=s88-nd-c-c0xffffffff-rj-k-no
	43b	200	30ms	https://www.youtube.com/yts/img/pixel-vfl3z5WfW.gif
	・・・

blacklistRequests

正規表現に一致するHTTPリクエストには固定のステータスコードを返す。

var c = test.openHttpClient();
var web = require('webbot');

test.beginTransaction();
test.beginStep("Check Website");

c.blacklistRequests("https://i\\.ytimg\\.com/.*", 204);
c.blacklistRequests(".*yt3.ggpht.com.*", 204);

var req = c.newGet("https://www.youtube.com/");
var res = web.execute(req);

test.endStep();
test.endTransaction();
  • blacklistRequests での返却値
	514856b	200	1462ms	https://www.youtube.com/
	5878b	200	17ms	https://www.youtube.com/yts/jsbin/scheduler-vfl3G47Co/scheduler.js
	・・・
	0b	204	0ms	https://i.ytimg.com/vi/FYVn2ne7hJc/hqdefault.jpg?sqp=-oaymwEWCMQBEG5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLD35p4cHO4FZrVP8dzLpSQEn2PwoQ
	・・・
	0b	204	0ms	https://i.ytimg.com/vi/xyaFPwzWS20/hqdefault.jpg?sqp=-oaymwEWCMQBEG5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLAWZwsWBeYp_VTp6-0NJxyAVNyO5A
	43b	200	13ms	https://www.youtube.com/yts/img/pixel-vfl3z5WfW.gif
	・・・

whitelistRequests

正規表現に一致するリストに無いHTTPリクエストには固定のステータスコードを返す。配列指定可。

var c = test.openHttpClient();
var web = require('webbot');

test.beginTransaction();
test.beginStep("Check Website");

c.whitelistRequests([
  ".*www.youtube.com.*",
], 204);

var req = c.newGet("https://www.youtube.com/");
var res = web.execute(req);
//req.execute();

test.endStep();
test.endTransaction();
  • whitelistRequests での返却値
	517492b	200	1374ms	https://www.youtube.com/
	5878b	200	24ms	https://www.youtube.com/yts/jsbin/scheduler-vfl3G47Co/scheduler.js
	・・・
	0b	204	0ms	https://i.ytimg.com/vi/FYVn2ne7hJc/hqdefault.jpg?sqp=-oaymwEWCMQBEG5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLD35p4cHO4FZrVP8dzLpSQEn2PwoQ
	・・・
	0b	204	0ms	https://i.ytimg.com/vi/x0zgWgzy8Ow/hqdefault.jpg?sqp=-oaymwEWCMQBEG5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLAhkXbjeKJ0s8iXTN4upWXXa5CGYA
	43b	200	14ms	https://www.youtube.com/yts/img/pixel-vfl3z5WfW.gif
	・・・

その他

csv からの値取得

行番号指定かランダム読み込み。

test.getCSV(name) の name 指定はリテラルである必要がある。変数では展開されずエラーとなる。
(LocalValidator では成功するが、NeuStar上だとエラー)

Error: script-exception: "Problem fetching CSV file"
  • 例 data.csv
Name,Age,MailAddress
Yamada,22,t-yamada@example.com
Aikawa,28,s-aikawa@example.com
Endo,21,endo@@example.com

行番号読み込み

// readCsv
function readCsv(csv){
  var array = [];
  for (var i = 0; i < csv.size(); i++) {
    var row = csv.get(i);
    array[i] = row;

    var name = row.get("Name");
    var age = row.get("Age");
    var mail = row.get("MailAddress");
    test.log('Name: ' + name + ' / Age: ' + age + ' / Mail: ' + mail);
  }
  return array;
}
var csv  = test.getCSV("data.csv");
var data = readCsv(csv);
test.log(data);

ランダム読み込み

var csv  = test.getCSV("data.csv");
var csv_row = csv.random();
var name = csv_row.get("Name");
var age = csv_row.get("Age");
var mail = csv_row.get("MailAddress");
test.log('Name: ' + name + ' / Age: ' + age + ' / Mail: ');

一時停止

Step 間に一時停止時間を設定。ミリ秒単位。30秒制限有り。(Local Validator だと制限はない模様)

var c = test.openHttpClient();
var web = require('webbot');

test.beginTransaction();
test.beginStep("Check Website1");
var req = c.newGet("https://www.youtube.com/");
req.execute();
test.endStep();

test.pause(30000);

test.beginStep("Check Website2");
var req = c.newGet("https://google.com/");
req.execute();
test.endStep();

test.endTransaction();

assert (異常終了)

異常終了させたい場合に使用。

test.assertTrue(false, "Assert!!!");

  • 出力例
WARN mm/dd hh:mm:ss b.n.w.a.a.Webmetric~ - ERROR: assertTrue() failed! Assert!!! at line 8
  • 出力例(validation.txt)
***** ERROR DETECTED *****
Error Message: assertTrue() failed! Assert!!!
Error Line Num: 8
***** ERROR DETECTED *****

APIリファレンスを見ると他にも似たような関数( fail、 assertFalse )があるが、いずれも見つからないエラーとなる。処理は停止するが美しくはない。

  • 出力例(validation.txt)
***** ERROR DETECTED *****
Error Message: TypeError: Cannot find function fail in object biz.neustar.wpm.api.Test.
Error Line Num: 9
***** ERROR DETECTED *****

Validate 時間制限

NeuStar 上での Validate は Script 全体の処理時間が 60秒を超過するとエラーとなる。

Script took too long and reached timeout limit.

制限緩和は行えないため、Local Validator で Validate を行った後、Bypass Validation を有効にしてスキップさせる。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?