Backend Development 10 min read

Distributed Control System FunTester: Updates, Local Deployment, Swagger Support, Async Execution, and Multi‑Request Features

The article introduces the DCS_FunTester framework, explains its naming, provides Swagger API access, details local deployment steps, describes a header‑based authentication change, outlines asynchronous test execution, multi‑request handling, progress tracking, and includes relevant Java code snippets for building and running the system.

FunTester
FunTester
FunTester
Distributed Control System FunTester: Updates, Local Deployment, Swagger Support, Async Execution, and Multi‑Request Features

After a period of reflection and development, the first round of updates for the Distributed Control System FunTester (DCS_FunTester) is released, fixing bugs, adding functional improvements, and completing local deployment support.

Project Naming

The project is named DCS_FunTester , where DCS stands for Distributed Control System and FunTester is the suffix. Currently it is a slave project, with a master project still under consideration. The slave can be deployed independently or in multi‑node mode, exposing HTTP interfaces on all slave nodes.

Swagger Support

Swagger is chosen as the optimal solution for API documentation. The documentation is available at http://106.53.152.151:8000/swagger-ui/#/ ; when deploying locally, replace the domain and port accordingly.

Local Deployment

The code has been pushed to Gitee for easy download and deployment. The main steps are:

Build FunTester

Clone the repository https://gitee.com/fanapi/tester (branch oker ) and use Gradle to run build or jar . No local Groovy SDK is required.

Build DCS_FunTester

Clone https://gitee.com/fanapi/dcs (branch master ), add the FunTester JAR to gradle.build (e.g., compile files('/Users/oker/Library/groovy-3.0.8/lib/funtester-1.0.jar') ), and build with Gradle.

Start Service

Run the service directly using java -jar **** & (Docker is not used yet).

Authentication Change

The previous design placed the secret key in request parameters, causing issues. It has been moved to the HTTP header , ignoring GET requests. This change applies only to the public testing service; local deployments can omit this filter.

Relevant filter code:

String headerKey = req.getHeader(DcsConstant.HEADER_KEY);
String method = requestWrapper.getMethod();
if (!method.equalsIgnoreCase("get") && (StringUtils.isEmpty(headerKey) || !headerKey.equalsIgnoreCase(DcsConstant.HEADER_VALUE))) {
    response.getOutputStream().write(Result.fail("验证失败!").toString().getBytes());
    return;
}

Asynchronous Test Execution

Previously test cases ran serially, leading to long response times. The update introduces asynchronous execution, allowing up to 10 seconds per request during internal testing.

Request model ( HttpRequest ) includes fields such as times , mode , thread , runup , and desc .

Controller snippet for async execution:

@PostMapping(value = "/post")
public Result tests(@Valid @RequestBody HttpRequest request) {
    if (!ThreadBase.needAbort()) return Result.fail();
    // extract parameters
    // ...
    if (mode.equalsIgnoreCase("ftt")) {
        Constant.RUNUP_TIME = runup;
        RequestThreadTimes task = new RequestThreadTimes(re, times);
        Concurrent concurrent = new Concurrent(task, thread, desc);
        return Result.success(execute(concurrent));
    }
    return Result.fail();
}

The execute method starts a new thread, records a unique mark , and stores the performance result in a ConcurrentHashMap for later retrieval.

Multi‑Request Support

The update adds support for sending a list of requests concurrently. Requests are stored in a list and can be retrieved sequentially, randomly, or via an index counter. Future work may include weighted traffic distribution.

Controller snippet for multi‑request handling:

@PostMapping(value = "/post2")
public Result tests2(@Valid @RequestBody HttpRequest2 request) {
    if (!ThreadBase.needAbort()) return Result.fail();
    JSONArray requests = request.getRequests();
    List
res = new ArrayList<>();
    requests.forEach(f -> res.add(FunRequest.initFromString(JSON.toJSONString(f)).getRequest()));
    // extract other parameters
    if (mode.equalsIgnoreCase("ftt")) {
        Constant.RUNUP_TIME = runup;
        ListRequestMode task = new ListRequestMode(res, times);
        Concurrent concurrent = new Concurrent(task, thread, desc);
        return Result.success(execute(concurrent));
    }
    return Result.success();
}

The custom class ListRequestMode extends FixedThread and executes each request using FunLibrary.executeSimlple .

Progress Retrieval

A new progress field was added to ThreadBase to expose the running status of a task. The progress can be queried via:

@GetMapping(value = "/progress")
public Result progeress() {
    String s = ThreadBase.progress == null ? "没有运行任务" : ThreadBase.progress.runInfo;
    return Result.success(s);
}

The runInfo string follows the format: runInfo = String.format("%s进度:%s %s ,当前QPS: %d", taskDesc, getManyString(ONE, (int) (pro * LENGTH)), getPercent(pro * 100), getQPS());

Overall, the article provides a comprehensive guide to building, deploying, and extending the DCS_FunTester framework, covering naming, Swagger documentation, local deployment, authentication, asynchronous execution, multi‑request handling, and progress monitoring.

Backenddistributed systemsJavaperformance testingSwaggerAsync Execution
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

login 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.