ツー

日常の記録

JMeterでcookieありで、かつそれぞれを別ユーザでアクセスしたい

JMeter負荷試験をやりたいけれど、ログインした先の画面をテストしたいのでつまりはcookieが必要で、cookieが書かれたファイルを読み込んでアクセスごとに別ユーザで負荷試験してほしかったんだけど、標準機能ではできなそうだったのでBeanShellサンプラーでそんな感じのものを作った。

構成

こんな感じのシナリオを用意して、スレッド数を上げて並列にアクセスして負荷を掛けていきたい。

ソース

BeanShellサンプラーテストユーザのcookie情報読込 でこんな感じのコードを張る。

import java.util.regex.*;

// 共通の設定項目
int allThreadNum       = ctx.getThreadGroup().getNumThreads();
int currentThreadNum   = ctx.getThread().getThreadNum();
vars.put("CURRENT_THREAD_NUM", "" + currentThreadNum);

String propFileName     = vars.get("TEST_PROP_FILENAME");
log.info("TEST_FILENAME: " + propFileName);

// propertiesファイルにあるテスト用のcookie値を全部jmeterの変数に入れる
try {
    FileInputStream infile = new FileInputStream(new File(propFileName));
    Properties prop = new Properties();
    prop.load(infile);

    int putCnt = 0;
    Enumeration it = prop.propertyNames();

    // スレッドグループで指定したスレッド数でユーザデータを分ける
    while(it.hasMoreElements()) {
        String key = it.nextElement();
        String val = prop.getProperty(key);

        Pattern p = Pattern.compile("(\\w+)_(\\d+)");
        Matcher m = p.matcher(key);

        if (!m.find()) {
            log.warn("!!!!!INVALID_KEY!!!!! " + key);
            continue;
        }
        
        int propKeyNum  = Integer.parseInt(m.group(2));
        int surplus     = propKeyNum % allThreadNum;

        if (surplus != currentThreadNum) {
            continue;
        }

        // 1から順番にデータを作らないとForEachコントローラが認識してくれないのでkey値を振り直しする
        String label    = m.group(1);
        String newKey = label + currentThreadNum + "_" + putCnt;
        vars.put(newKey, val);

        putCnt++;
    }

    log.info("ThreadNum=" + currentThreadNum + " PutCnt=" + putCnt);
} catch (Exception e) {
    print("!!!!!ERROR!!!!! " + e);
}

BeanShell PreProcessorの cookieをセット でこんな感じのコードを張る。

import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.protocol.http.control.Cookie;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.testelement.property.CollectionProperty;

CookieManager manager = ctx.getCurrentSampler().getCookieManager();
Cookie cookie = new Cookie();

String cookieKey = vars.get("loopValue");
String cookieEnvelope = cookieKey;
log.info(cookieKey);

cookie.setDomain(vars.get("DOMAIN"));
cookie.setName(vars.get("COOKIE_KEY"));
cookie.setValue(cookieEnvelope);

CollectionProperty p = manager.getCookies();

if (p.size() != 0) {
    // cookieがある場合とない場合があるのである場合は古いのを消す
    p.clear();
}

manager.add(cookie);

必要な変数や環境変数は以下。

  • TEST_PROP_FILENAME : cookieの一覧を詰めたpropertiesファイルを指定する
  • DOMAIN : cookieを設定するドメインを指定する
  • COOKIE_KEY : cookieのキー値を設定する
  • loopValue : ループでのoutput変数名に指定する

propertiesファイルはこんな感じのを用意すればOK。

test_1=cookieの値1
test_2=cookieの値1

注意点が一つあり、ForEachコントローラーは1から順にインクリメントしていってキーがなかったらループ終了という動作をするので、propertiesのキー値を均等に分けるだけでは番号が飛ぶので要素が無い判定されてループしないのだけは注意。これで半日くらいハマって全然わからなかったのでGitHubのソースを見に行って解決した。

とりあえずは期待通りに動作したけど、大きい負荷を掛けた時に思った通りに動くかどうかはわからない。

まとめ

JMeterを初めて触ったので、既存の機能に既にあったり間違っていたりする可能性はある。