Operations 9 min read

How to Build a Distributed Performance Testing Framework with DCS_FunTester and Docker

This article details a practical implementation of a distributed performance testing framework using DCS_FunTester, describing the master‑slave architecture, Docker image setup, Groovy/Java scripts, sample code, console output, and server logs to help engineers replicate the approach.

FunTester
FunTester
FunTester
How to Build a Distributed Performance Testing Framework with DCS_FunTester and Docker

Architecture Overview

The article documents a hands‑on extension of the DCS_FunTester framework to enable distributed performance testing. The system consists of three components: a master scheduler that receives test cases and distributes tasks, one or more slave test nodes that execute the received scripts, and the server under test that provides the testing API.

Master Scheduler

The master node receives a test case, packages the Groovy or Java script, and uploads it to the slave nodes for execution. For this proof‑of‑concept only a single slave node is used, and a fixed‑thread, fixed‑request‑count load model is applied.

Master Script

package com.mocofun.moco.main

import com.alibaba.fastjson.JSONObject
import com.funtester.base.bean.Result
import com.funtester.utils.RWUtil
import com.mocofun.moco.MocoServer

class DcsServer3 extends MocoServer {
    public static void main(String[] args) {
        def server = getServer(12345)
        def res = new JSONObject()
        res.script = RWUtil.readTxtByString("/Users/oker/IdeaProjects/funtester/src/test/groovy/com/funtest/groovytest/Share.groovy")
        server.get(urlStartsWith("/m")).response(obRes(Result.success(res)))
        def run = run(server)
        waitForKey("fun")
        run.stop()
    }
}

Test Case

package com.funtest.groovytest

import com.funtester.config.Constant
import com.funtester.frame.execute.Concurrent
import com.funtester.frame.thread.RequestThreadTimes
import com.funtester.httpclient.ClientManage
import com.funtester.httpclient.FunLibrary
import com.funtester.utils.ArgsUtil
import org.apache.http.client.methods.HttpGet

class Share extends FunLibrary {
    public static void main(String[] args) {
        ClientManage.init(10, 5, 0, "", 0);
        def util = new ArgsUtil(args)
        int thread = util.getIntOrdefault(0, 20);
        int times = util.getIntOrdefault(1, 100);
        String url = "http://localhost:12345/m";
        HttpGet get = getHttpGet(url);
        Constant.RUNUP_TIME = 0;
        RequestThreadTimes task = new RequestThreadTimes(get, times);
        new Concurrent(task, thread, "Local Fixed QPS Test").start();
    }

    public static void test(String params) {
        main(params.split(COMMA))
    }
}

Slave Test Node

package com.funtest.groovytest

import com.funtester.frame.execute.ExecuteGroovy
import com.funtester.httpclient.FunLibrary

class Dcs3 extends FunLibrary {
    public static void main(String[] args) {
        while (true) {
            String url = "http://localhost:12345/m"
            def get = getHttpGet(url)
            def response = getHttpResponse(get)
            if (response.getInteger("code") == 0) {
                def data = response.getJSONObject("data")
                def script = data.getString("script")
                ExecuteGroovy.executeScript(script)
            }
            sleep(5.0)
            fail()
        }
    }
}

Console Output

INFO-> 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO-> 请求uri:http://localhost:12345/m , 耗时:463 ms , HTTPcode: 200
INFO-> =========预热完成,开始测试!=========
INFO-> 本地固定QPS测试进度:▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍  100%
INFO-> 总计20个线程,共用时:0.754 s,执行总数:1933,错误数:0,失败数:0
INFO-> 数据保存成功!文件名:/Users/oker/IdeaProjects/funtester/long/data/本地固定QPS测试251800_20

Performance Result

Performance test result
Performance test result

Server Log

Content-Length: 1089
Content-Type: text/plain; charset=utf-8

{"code":0,"data":{"script":"package com.funtest.groovytest;

import com.funtester.config.Constant;
import com.funtester.frame.execute.Concurrent;
import com.funtester.frame.thread.RequestThreadTimes;
import com.funtester.httpclient.ClientManage;
import com.funtester.httpclient.FunLibrary;
import com.funtester.utils.ArgsUtil;
import org.apache.http.client.methods.HttpGet;

class Share extends FunLibrary {

    public static void main(String[] args) {
        ClientManage.init(10, 5, 0, \"\", 0);
        def util = new ArgsUtil(args)
        int thread = util.getIntOrdefault(0, 20);
        int times = util.getIntOrdefault(1, 100);
        String url = \"http://localhost:12345/m\";
        HttpGet get = getHttpGet(url);
        Constant.RUNUP_TIME = 0;
        RequestThreadTimes task = new RequestThreadTimes(get, times);
        new Concurrent(task, thread, \"Local Fixed QPS Test\").start();
    }

    public static void test(String params) {
        main(params.split(COMMA))
    }

}
"}}
Request received:

GET /favicon.ico HTTP/1.1
Host: localhost:12345
Connection: keep-alive
... (truncated)
Response return:

HTTP/1.1 400

The article concludes that the single‑node version of the distributed framework is still in internal testing, and readers are invited to follow future updates via the author’s public account.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DockerPerformance TestingDistributed TestingGroovy
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.