Chapter 21Lesson 05~260 minutes

Checkpoint Lab — CLI Mode, Headless Execution, Result Files, and Reproducible Runs

The checkpoint treats a CLI run as an immutable evidence bundle. You will first prove a successful eight-sample run, then create a deliberate missing-JMX engine failure and preserve its non-success evidence, then restore a second successful run from a clean shell. The comparison must show that only run identity/output paths changed—not input hashes, workload or target behavior.

CheckpointRun manifestMissing-file failureHTML reportClean-shell replay

Learning objectives

  • Execute a cross-platform-oriented launcher with bounded local workload.
  • Produce isolated JTL/log/report/version/hash/command/gate/manifest artifacts.
  • Predict successful and missing-file execution outcomes before running.
  • Trigger and preserve one genuine JMeter missing-JMX process failure.
  • Restore a clean successful run without deleting or mutating failed evidence.
  • Verify configured versus achieved sample counts and target events independently.

1. Exact assumptions and hard ceilings

Item Checkpoint baseline
JMeter Apache JMeter 5.6.3.
Java Java 17 JDK; JMeter 5.6.3 requires Java 8+.
Plugins None.
Target http://127.0.0.1:8021 only.
Fixture Python stdlib prompt21-cli-fixture-v1.
Plan plans/cli-local.jmx.
Properties config/local.properties via -q.
Run property -Jrun.id=<unique>.
Load 2 threads ×4 loops = 8 work samples.
Pacing 20 ms Constant Timer.
Result CSV JTL + explicit jmeter.log.
Report -e -o <new run-dir>/html-report.
Gate expected samples=8; failures=0; lab p95≤500 ms.
Failure case missing JMX direct CLI; no production target or failure injection.
Abort: non-loopback target, >2×4 configured samples, existing run directory collision, missing/changed input hash between intended equivalent runs, unexpected target event count, sustained generator saturation, secrets in command/manifest, or any attempt to use -f on an unchecked path.

2. Setup / preflight

  1. Create fixture, property file, JMX, launcher, gate/manifest/analyzer scripts from Lesson 2.
  2. Start fixture on 127.0.0.1:8021 with a fresh JSONL event log.
  3. GET /health//stats and record baseline work count.
  4. Record JMeter/Java version and SHA-256 of JMX/properties.
  5. Verify results/p21-check-a does not exist.

3. Predictions before the successful run

Prediction A — artifacts: launcher creates one new run directory containing command/version/pre-manifest, JTL, jmeter.log, engine/gate exit files, HTML report and final manifest.

Prediction B — workload: exactly eight successful Work samples appear in JTL and exactly eight matching target events occur: four for T1 and four for T2.

Prediction C — status: engine exit=0 and gate exit=0 when row count, failures and lab p95 are valid.

4. Successful run A

PowerShell:

Set-Location "F:\Labs\p21-cli-lab"
.\tools\run-local.ps1 -RunId p21-check-a
$LASTEXITCODE

Or Bash:

cd /path/to/p21-cli-lab
./tools/run-local.sh p21-check-a
printf 'wrapper_exit=%s
' "$?"

5. Verify run A

  • engine-exit.txt = 0;
  • gate-exit.txt = 0;
  • gate.json = PASS, samples=8, failures=0, p95≤500;
  • JTL has header + 8 sample data rows;
  • jmeter.log has no unexplained ERROR/FATAL;
  • html-report/index.html exists;
  • run-manifest.json contains exact command, versions, hashes and paths.
python tools/analyze_events.py results/server-events.jsonl p21-check-a

Require eight target work events with four per thread.

6. Predict the intentional missing-file failure

Prediction D: directing raw JMeter at plans/missing-plan.jmx produces non-success engine/process evidence before the normal eight-sample workload. The target should receive zero work events for the missing-run ID, and the safe launcher's historical run A must remain untouched.

7. Execute the missing-JMX diagnostic

PowerShell:

$ProjectRoot = "F:\Labs\p21-cli-lab"
$FailDir = Join-Path $ProjectRoot "results\p21-missing"
if (Test-Path $FailDir) { throw "Failure evidence directory already exists." }
New-Item -ItemType Directory $FailDir | Out-Null

$Command = @(
  "$env:JMETER_HOME\bin\jmeter.bat","-n",
  "-t",(Join-Path $ProjectRoot "plans\missing-plan.jmx"),
  "-q",(Join-Path $ProjectRoot "config\local.properties"),
  "-Jrun.id=p21-missing",
  "-l",(Join-Path $FailDir "results.jtl"),
  "-j",(Join-Path $FailDir "jmeter.log")
)
$Command -join " " | Set-Content (Join-Path $FailDir "command.txt")

& $Command[0] $Command[1..($Command.Count-1)]
$EngineExit = $LASTEXITCODE
$EngineExit | Set-Content (Join-Path $FailDir "engine-exit.txt")

Bash:

PROJECT_ROOT=/path/to/p21-cli-lab
FAIL_DIR="$PROJECT_ROOT/results/p21-missing"
[[ ! -e "$FAIL_DIR" ]] || { echo "Failure dir exists" >&2; exit 2; }
mkdir -p "$FAIL_DIR"

"$JMETER_HOME/bin/jmeter"   -n   -t "$PROJECT_ROOT/plans/missing-plan.jmx"   -q "$PROJECT_ROOT/config/local.properties"   -Jrun.id=p21-missing   -l "$FAIL_DIR/results.jtl"   -j "$FAIL_DIR/jmeter.log"
ENGINE_EXIT=$?
printf '%s
' "$ENGINE_EXIT" >"$FAIL_DIR/engine-exit.txt"

Do not use -f. Do not delete the failure directory after observing the expected error.

8. Verify non-success evidence

Require:

  • non-zero engine/process exit;
  • jmeter.log or console evidence identifies the missing/unloadable JMX path;
  • no valid eight-row workload for p21-missing;
  • python tools/analyze_events.py results/server-events.jsonl p21-missing reports zero work events;
  • run A artifacts/hashes are unchanged.

This is an engine/input failure, not an SLO failure.

9. Restore with the validated launcher from a clean shell

PowerShell:

Set-Location "$env:TEMP"
& "F:\Labs\p21-cli-lab\tools\run-local.ps1" -RunId p21-check-b
$LASTEXITCODE

Run B must create a new directory and use the real cli-local.jmx without touching p21-missing.

10. Compare successful run A and B

Verify in both manifests:

  • same JMX SHA-256;
  • same property-file SHA-256;
  • same JMeter/Java expected baseline;
  • same configured 2×4/20 ms load and eight achieved successful samples;
  • same target operation distribution;
  • different run IDs/output directories and possibly caller cwd;
  • both reports reconstruct from their retained JTL.

11. Prove report reproducibility from raw JTL

Generate a second report from run A:

& "$env:JMETER_HOME\bin\jmeter.bat" `
  -g "F:\Labs\p21-cli-lab\results\p21-check-a\results.jtl" `
  -o "F:\Labs\p21-cli-lab\results\p21-check-a\html-report-rebuilt"

The rebuilt report is derived from preserved raw results; no target traffic is generated.

12. Generator/measurement validity

Record generator CPU/memory/network/disk during one successful run. The workload is intentionally tiny; the expected conclusion is only that the CLI/evidence mechanics are valid under local headroom.

Configured load = 8 work samples. Achieved load = 8 successful JTL samples and 8 target events. Never turn this localhost number into a production capacity statement.

13. Required evidence packet

Artifact Required content
Exact CLI/command command.txt or manifest tokens for each successful/failure invocation.
Versions JMeter and Java captured for successful runs.
Input hashes SHA-256 JMX + property file.
Run directory Unique p21-check-a, p21-missing, p21-check-b paths.
JTL 8 successful rows for each valid run; partial/absent for missing JMX as expected.
jmeter.log Run-specific engine log; failure log preserved.
HTML report At-end report plus one later -g rebuild.
Process exit engine-exit.txt; missing-JMX run non-zero.
Gate gate-exit/gate.json separate from engine process.
Manifest command/paths/hashes/versions/artifacts/exits/gate summary.
Target evidence 8 work events for each valid run; zero for missing-JMX run ID.

14. Validity statement

Example: “Apache JMeter 5.6.3/Java 17 executed cli-local.jmx against prompt21-cli-fixture-v1 at 127.0.0.1:8021 through a wrapper that created immutable run directories, captured the exact CLI, tool versions and SHA-256 input hashes, wrote CSV JTL and run-specific jmeter.log, generated an HTML report with -e -o, recorded the engine exit, and independently gated expected row count/failures/lab p95. Two successful runs from different caller directories produced the same input hashes, eight valid JTL samples and eight target work events. A direct CLI invocation of a nonexistent JMX produced preserved non-success engine/log evidence and zero matching target work; no prior artifacts were deleted. A later -g command rebuilt a report from retained JTL without target traffic. This validates the local CLI/reproducibility/evidence workflow, not production service capacity.”

15. Verification checklist

  • Target exactly 127.0.0.1:8021.
  • JMeter 5.6.3 / Java 17 / no plugins recorded.
  • No load run in GUI.
  • Safe wrapper never uses -f and refuses existing run IDs.
  • JMX/property SHA-256 recorded.
  • Valid runs have engine exit=0 and independent gate=0.
  • Each valid run has exactly eight JTL samples and eight target work events.
  • Missing-JMX run has non-success engine evidence and zero target work.
  • HTML report exists and can be regenerated later from JTL.
  • No secrets appear in commands, properties, logs or manifests.

16. Cleanup / rollback

  1. Stop the localhost fixture after target evidence is captured.
  2. Keep JTL/jmeter.log/reports/manifests/version/hash/failure evidence until review completes.
  3. Delete only disposable local run directories after review; never delete historical evidence as part of rerun startup.
  4. No public/production API, credential, recorder certificate, remote RMI engine, container, database/message service, paid platform, CI secret or OS/JVM global tuning was changed.

17. What Chapter 21 adds to the operating model

The production performance-testing operating model now has a headless execution/evidence contract: approved JMeter/Java versions; explicit JMX/property/data hashes; safe CLI flags; immutable run directory; raw JTL; run-specific jmeter.log; optional reproducible dashboard; exact command; process exit; independent correctness/performance gate; generator resource evidence; target operation evidence; and retention/cleanup rules are required before a run becomes CI/scheduled release evidence.

Chapter 22 moves to Listeners, Result Collection, Memory Cost, and Safe Debugging. It deepens the result-side contract by showing which listeners are safe during authoring/load, what they retain in memory, how result fields/save settings change cost, and how to debug without invalidating the generator.

Knowledge check

Why must the missing-JMX failure remain in a separate directory?

What proves run A and B are reproducible equivalents?

Why is a rebuilt -g report useful evidence?

If engine exit is zero but gate exit is 30, what failed?

What is Chapter 22's bridge?

Next chapter

Listeners, Result Collection, Memory Cost, and Safe Debugging

Chapter 22 focuses on result capture costs, listener selection, safe GUI debugging and lean load-mode evidence.

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against current Apache JMeter primary documentation on 2026-09-05. The course baseline remains Apache JMeter 5.6.3 with a Java 17 JDK; JMeter 5.6.3 requires Java 8+. JMeter's own manual says GUI mode is for building/debugging while CLI mode must be used for load testing. Current CLI flags include -n (CLI), -t (JMX), -l (JTL), -j (run log), -g <CSV> (report only), -e (report after test), and -o (report output). The report output folder must not exist or must be empty. -f force-deletes an existing result file/report folder before a test, so the safe launcher in this chapter intentionally does not use it; instead it refuses to reuse an existing run directory. CSV result files are smaller than XML and are the normal large-run choice. Current CSV defaults include timing/status/thread and byte fields such as timeStamp, elapsed, label, responseCode, success, bytes, sentBytes, grpThreads, and allThreads when their save-service fields are enabled (the current defaults required by the dashboard are documented as correct unless changed). Response data is not supported in CSV. JMeter process/engine completion is therefore treated separately from a post-run SLO/result gate: a launcher first records the engine exit code, then validates JTL sample counts/failures/latency. A zero engine exit is not used as evidence that every sample met an SLO.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.