Chapter 08Lesson 05~215 minutes

Checkpoint Lab — Assertions and Functional Correctness Under Load

The checkpoint combines correctness and performance evidence. A tiny local plan intentionally produces a true success, an HTTP 503 protocol failure, and an HTTP 200 business rejection. Minimal assertions must classify all three correctly, generate dashboard errors, and demonstrate their injector cost relative to an assertion-free baseline.

CheckpointClassificationFailure messagesDashboardOverhead comparison

Learning objectives

  • Build three clearly labeled samplers for success, protocol-error, and business-error variants.
  • Apply only assertions required to classify each result correctly.
  • Predict response code, SampleResult success, and assertion failure message before running.
  • Generate dashboard error evidence from a lean CSV JTL.
  • Compare a no-assertion success baseline with a minimally asserted success profile.
  • State what assertion evidence proves and what the small loopback lab cannot establish.

1. Assumptions and safety limits

Item Checkpoint baseline
JMeter Apache JMeter 5.6.3.
Java Java 17 JDK lab baseline; JMeter 5.6.3 requires Java 8+.
Plugins None.
Target http://127.0.0.1:8000 only.
Classification load 1 thread × 5 loops × 3 samplers = 15 target requests.
Overhead baseline 2 threads × 25 loops × Success only = 50 requests.
Overhead asserted Same 50-request profile + Response Code and JMESPath assertions.
Dashboard Generated from CSV JTL with assertion failure messages enabled.
Secrets None; all payloads and error codes are synthetic.
Abort: wrong target, unexpected external URL, workload above stated ceilings, unexpected protocol errors outside the deliberate Protocol Error sampler, or unsafe generator pressure. Do not increase loops because an overhead delta is hard to measure.

2. Start a clean fixture

mkdir -p results/checkpoint-classify results/overhead-baseline results/overhead-asserted
python fixtures/assertion_fixture.py --log results/checkpoint-classify/server-events.jsonl
curl --fail --silent http://127.0.0.1:8000/health

Restart the fixture before overhead runs if you want isolated event logs. The server responses are deterministic enough for the course, but workstation scheduling noise still affects micro-benchmarks.

3. Build the classification plan

Test Plan — Chapter 08 Checkpoint
└── Thread Group — 1 user × 5 loops
    ├── HTTP Request Defaults — HttpClient4 / 127.0.0.1:8000
    ├── Success — GET /success
    │   ├── Response Assertion — Response Code Equals 200
    │   └── JSON JMESPath Assertion — business Equals accepted
    ├── Protocol Error — GET /protocol-error
    │   └── Response Assertion — Response Code Equals 200
    └── Business Error — GET /business-error
        ├── Response Assertion — Response Code Equals 200
        └── JSON JMESPath Assertion — business Equals accepted

Keep Ignore Status off everywhere. The Protocol Error sampler must remain failed because 503 is not an expected normal success.

4. Predict classification before execution

Label HTTP code Business field Expected final success Reason
Success 200 accepted true Transport and business assertions pass.
Protocol Error 503 not_evaluated false HTTP sampler is unsuccessful and code-200 assertion also fails.
Business Error 200 rejected false Transport passes; JMESPath business assertion fails.

Prediction 1: HTTP code alone distinguishes Protocol Error but not Business Error. Prediction 2: the dashboard should show two failed sampler populations with different failure reasons.

5. One bounded GUI verification

Run one loop with View Results Tree and Assertion Results only for authoring. Verify:

  • Success has no assertion failures;
  • Protocol Error remains failed with HTTP 503;
  • Business Error remains HTTP 200 but has an assertion failure;
  • failure messages name the violated invariant rather than dumping the full response.

Disable both listeners before the five-loop checkpoint run.

6. Run classification from CLI and generate dashboard

jmeter -n   -t plans/checkpoint-classify.jmx   -l results/checkpoint-classify/results.jtl   -j results/checkpoint-classify/jmeter.log   -e -o results/checkpoint-classify/report   -Jjmeter.save.saveservice.print_field_names=true   -Jjmeter.save.saveservice.successful=true   -Jjmeter.save.saveservice.response_code=true   -Jjmeter.save.saveservice.response_message=true   -Jjmeter.save.saveservice.thread_counts=true   -Jjmeter.save.saveservice.assertion_results_failure_message=true
python tools/analyze_assertions.py results/checkpoint-classify/results.jtl
curl --fail --silent http://127.0.0.1:8000/stats

PowerShell uses jmeter.bat with the same settings. The report directory must not already contain a previous report.

7. Expected classification evidence

With 5 loops:

  • Success: 5 successful samples;
  • Protocol Error: 5 failed samples with response code 503;
  • Business Error: 5 failed samples with response code 200 plus JMESPath/business assertion message;
  • overall: 15 samples, 10 failures, ~66.7% error rate by design.

This deliberately high error percentage is not a service-quality claim—it is a synthetic classification lab with two failure variants intentionally executed every loop.

8. Verify dashboard error table

In report/index.html, confirm:

  • request summary reflects 5 successful / 10 failed samples;
  • Error table contains the synthetic failure reasons;
  • Top 5 Errors by Sampler separates Protocol Error and Business Error labels;
  • Statistics table keeps label-level counts/timing visible.

Cross-check raw JTL before trusting dashboard grouping.

9. Prepare a clean overhead comparison

Create two separate Success-only plans:

  1. overhead-baseline.jmx: 2 threads × 25 loops, GET /success, no assertions.
  2. overhead-asserted.jmx: identical workload plus code=200 and business=accepted JMESPath assertions.

No debug listener, no dashboard generation during the timed command itself if you want to isolate test-engine overhead. Generate dashboards afterward from the JTL when needed.

10. Run and measure assertion overhead

Bash example:

/usr/bin/time -p jmeter -n   -t plans/overhead-baseline.jmx   -l results/overhead-baseline/results.jtl   -j results/overhead-baseline/jmeter.log

/usr/bin/time -p jmeter -n   -t plans/overhead-asserted.jmx   -l results/overhead-asserted/results.jtl   -j results/overhead-asserted/jmeter.log

python tools/compare_runs.py   results/overhead-baseline/results.jtl   results/overhead-asserted/results.jtl

PowerShell:

Measure-Command {
  jmeter.bat -n `
    -t plans\overhead-baseline.jmx `
    -l results\overhead-baseline\results.jtl `
    -j results\overhead-baseline\jmeter.log
}

Measure-Command {
  jmeter.bat -n `
    -t plans\overhead-asserted.jmx `
    -l results\overhead-asserted\results.jtl `
    -j results\overhead-asserted\jmeter.log
}

python tools\compare_runs.py `
  results\overhead-baseline\results.jtl `
  results\overhead-asserted\results.jtl

Record Task Manager/top CPU/memory during both runs. If the small narrow-assertion overhead is below noise, state that rather than exaggerating. Repeat a few times only if needed, keeping the same 50-request ceiling per run.

11. Interpret overhead correctly

Minimal assertions may leave sampler p50/p95 almost unchanged because the target service interval is the same. Assertion work happens after the sampler and can instead affect thread availability, achieved throughput, total engine wall time, and generator CPU.

A measurable slowdown in the asserted plan does not prove the target got slower unless server event timing or sampler elapsed also changed consistently.

12. Required evidence packet

Artifact Required content
Checkpoint JMX Three stable labels and narrow assertion scope.
Assertion configuration note Response code/JMESPath settings, Ignore Status off.
Raw classification JTL success, code/message, assertion failure messages.
Classification jmeter.log Engine/runtime evidence.
Dashboard Request summary, Error table, Top 5 Errors by Sampler.
Server event log/stats Independent target codes/service timing/request counts.
Baseline/asserted JTL + logs Identical Success-only workload except assertion layer.
Overhead comparison Whole-run timing, JTL throughput/p50/p95, generator CPU/memory.
Validity statement Synthetic failure mix and tiny loopback workload are not production-capacity evidence.

13. Verification checklist

  • Target is exactly loopback:8000.
  • Classification plan produces 15 samples maximum.
  • Success is green; Protocol Error is failed 503; Business Error is failed HTTP 200.
  • Ignore Status is off in normal success/failure classification.
  • JTL contains assertion failure messages.
  • Dashboard counts match raw JTL.
  • Assertion Results/View Results Tree are absent from load copies.
  • Baseline and asserted overhead plans differ only by minimal assertions.
  • Generator CPU/memory is recorded before making overhead claims.

14. Validity statement

Example: “Using JMeter 5.6.3 and Java 17 against a synthetic loopback service, Response Code and JSON JMESPath assertions correctly classified a normal 200/accepted response as success, an HTTP 503 response as protocol failure, and an HTTP 200/rejected response as business failure. JTL assertion failure messages and the HTML dashboard error tables preserved both failure populations. A separate 50-request Success-only baseline/asserted comparison quantified generator-side assertion cost; sampler latency was interpreted separately from whole-run throughput and generator CPU. This proves the configured assertion semantics on the local fixture, not production capacity, business-rule completeness, or zero assertion overhead at larger scale.”

15. Cleanup

  1. Stop the local fixture.
  2. Keep classification and overhead evidence until review is complete.
  3. Remove debug listeners from later load profiles.
  4. Do not carry synthetic failure percentages into production reporting.
  5. No production target, real credential, recorder certificate, remote engine, database, container, plugin, or system-wide JVM/OS setting was changed.

16. What Chapter 08 adds to the operating model

The performance-testing operating model now has a correctness contract: each critical sampler defines transport/business invariants, assertion scope, expected failure classification, failure-message retention, dashboard grouping, and acceptable injector overhead.

Chapter 09 naturally extends this by extracting dynamic response data and correlating requests so correctness assertions can validate realistic session-dependent values rather than only static synthetic fields.

Knowledge check

Why does Business Error count as failed even though responseCode is 200?

Why is Protocol Error not made green with Ignore Status?

What dashboard evidence should match raw JTL?

Why can the asserted overhead plan have similar sampler p95 but lower overall throughput?

What is the natural bridge to Chapter 09?

Next chapter

Extractors, Correlation, Dynamic Data, and Session-Aware Requests

Chapter 09 will make assertions and requests depend on values extracted from previous responses, preserving per-thread correctness across dynamic sessions.

Official references and version notes

Version and compatibility note

Version-sensitive behavior was 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 for labs and no third-party plugins; JMeter 5.6.3 requires Java 8+. Response Assertion can evaluate response text, response code/message, headers, request data, URL, or a JMeter variable. Its Ignore Status option forces the response status to successful before evaluating that assertion and can clear earlier assertion failures, so it is a specialized first-assertion behavior rather than a generic way to turn infrastructure failures into passes. JSON Assertion and JSON JMESPath Assertion both parse JSON and fail when their required path cannot be found; JMESPath can also compare an expected value. Duration Assertion marks samples failed when elapsed response time exceeds its threshold. Size Assertion validates response byte count. JMeter's Assertion Results listener is explicitly documented as unsuitable for load tests because of CPU/memory cost; use it only for bounded debugging. The HTML dashboard includes failed-request summaries, an error table, and Top 5 Errors by Sampler. Dashboard-compatible CSV requires fields including success, response code/message, timing, thread counts, and assertion failure messages, which are enabled by default in the current release and are also made explicit in chapter CLI examples.

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.