Chapter 12Lesson 05~230 minutes

Checkpoint Lab — Controllers: Simple, Loop, Transaction, If, While, Switch, and Throughput

The checkpoint turns controller structure into measurable workload evidence. You will run a deterministic browse/search/poll/checkout journey, verify exact child and transaction counts, then introduce one loop/scope defect whose symptom must be explained from JTL labels and independent target counts.

CheckpointPredicted countsTransaction labelsDefect diagnosisOperating model

Learning objectives

  • Build a complete controller tree with explicit branch/loop semantics.
  • Predict target request count and CSV JTL row count before execution.
  • Verify branch/loop behavior independently using server events.
  • Compare additional transaction mode with parent mode.
  • Introduce and diagnose one bounded loop/scope defect.
  • Produce a controller evidence packet suitable for CI/baseline review.

1. Assumptions and hard ceilings

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.
Threads 1 for valid checkpoint; max 2 in optional comparison.
Outer iterations 2 valid; max 10 only for isolated Throughput percentage demo.
Search Loop 2 per outer iteration.
While Poll 2 per outer iteration via response-derived POLL_MORE.
Checkout If=true, Switch=standard.
Upsell Throughput Controller Total Executions=1, Per User off.
Failure reproduction 1 thread, duration ≤4 s, 200 ms poll timer.
Abort: wrong/external target, unexpected loop growth beyond safety prediction, duration above the stated ceiling, unexpected 5xx outside deliberate error paths, or unsafe generator pressure.

2. Start clean and archive the tree

mkdir -p results/checkpoint results/parent results/broken results/repaired
python fixtures/controller_fixture.py --log results/checkpoint/server-events.jsonl
curl --fail --silent http://127.0.0.1:8000/health
curl --fail --silent http://127.0.0.1:8000/reset

Save/export the exact controller tree and resolved variables before running. The evidence packet should show every loop count, branch condition, Switch value, Throughput mode/count, and Transaction option.

3. Valid checkpoint tree

Thread Group — 1 thread × 2 iterations
└── Transaction Controller — Journey Transaction
    Parent: OFF
    Include timers/pre-post: OFF
    ├── Simple — Browse Phase
    │   └── Browse
    ├── Loop — SearchLoop ×2
    │   └── Search
    ├── Poll Reset → extractor POLL_MORE=true
    ├── While — WaitForReady (${POLL_MORE})
    │   └── Poll → extractor updates POLL_MORE (true then false)
    ├── If — Do Checkout (${DO_CHECKOUT}=true)
    │   └── Switch (${CHECKOUT_MODE}=standard)
    │       ├── standard → Checkout Standard
    │       ├── express → Checkout Express
    │       └── default → Checkout Default
    └── Throughput Controller — Upsell
        Total executions=1; Per User=OFF
        └── Upsell

4. Required predictions before execution

Prediction A — target requests:

Per outer iteration:
Browse 1
Search 2
Poll Reset 1
Poll 2
Checkout 1
= 7

Two outer iterations = 14
Upsell total-executions branch = 1
Expected target requests = 15

Prediction B — JTL rows, Transaction parent OFF:

15 child protocol rows + 2 transaction rows = 17 CSV rows

Prediction C — Transaction parent ON: target still receives 15 requests, but CSV JTL should contain two parent transaction rows rather than 15 separate child rows.

5. Run the valid checkpoint

jmeter -n   -t plans/checkpoint-controllers.jmx   -l results/checkpoint/results.jtl   -j results/checkpoint/jmeter.log   -Jjmeter.save.saveservice.print_field_names=true   -Jjmeter.save.saveservice.thread_counts=true

python tools/analyze_jtl_labels.py results/checkpoint/results.jtl
python tools/analyze_server_events.py results/checkpoint/server-events.jsonl
curl --fail --silent http://127.0.0.1:8000/stats

6. Verify valid-run counts

Expected target endpoint counts:

Endpoint Expected count
/browse 2
/search 4
/poll-reset 2
/poll 4
/checkout 2
/upsell 1
Total 15

Expected additional transaction label count: Journey Transaction = 2. No transaction label should appear in the server event log.

7. Verify parent-sample reporting separately

Reset fixture and rerun the same journey with Generate Parent Sample=ON into results/parent/. Verify:

  • target endpoint counts remain 15;
  • CSV JTL contains two Journey Transaction parent rows;
  • child HTTP results are sub-samples, not separate CSV rows;
  • transaction success becomes false if any nested child fails.

8. Deliberate defect — Poll extractor scoped to Poll Reset only

Create a broken copy where the JSON extractor that updates POLL_MORE after Poll is mistakenly moved under Poll Reset. Now Poll responses no longer set false, so While would continue.

Contain the reproduction:

  • 1 thread;
  • Thread Group duration 4 seconds;
  • 200 ms Constant Timer under Poll;
  • abort if target Poll count exceeds 20.

Run into results/broken/. Expected: Poll count materially exceeds the valid count of two per journey while other child counts may not be reached because the thread remains inside While.

9. Diagnose the defect from evidence

Required interpretation:

  1. JTL shows repeated Poll label.
  2. Server event log independently confirms repeated /poll target requests.
  3. POLL_MORE never receives the Poll response's false value because extractor scope is wrong.
  4. The server is responding normally; the generator's controller state is causing excess traffic.
  5. Thread Group duration prevents an unbounded safety incident but does not repair the business logic.

10. Repair the smallest layer

Restore the JSON extractor as a Post-Processor of Poll with default false. Keep the same Thread Group/While/fixture settings and rerun into results/repaired/.

Expected: Poll returns to exactly two executions per journey, the later Checkout/Upsell path executes, and request/JTL counts return to the valid predictions.

11. Optional second defect — wrong Loop Controller count

Change SearchLoop from 2 to 3 for one bounded run. Predict the delta before running:

2 outer iterations × +1 extra Search = +2 target requests and +2 Search JTL rows

This defect is useful for proving multiplicative loop math without involving server errors.

12. Generator/validity observation

Record Task Manager/top CPU/memory during valid and broken runs. The valid lab is tiny and should leave large injector headroom. If the generator is unexpectedly saturated, do not use the result to infer target capacity.

13. Required evidence packet

Artifact Required content
Controller tree Simple/Loop/Transaction/If/While/Switch/Throughput structure and options.
Resolved branch state DO_CHECKOUT, CHECKOUT_MODE, POLL_MORE lifecycle.
Prediction sheet Target endpoint counts and expected CSV JTL rows.
Valid JTL + jmeter.log Child and Journey Transaction labels.
Server event log/stats Independent real-request counts by endpoint.
Parent-mode run Two parent transaction CSV rows + unchanged target request counts.
Broken run Repeated Poll labels/events under hard duration guard.
Repair run Restored two Polls/journey and downstream branch execution.
Generator observation CPU/memory headroom and validity note.

14. Verification checklist

  • Target is exactly loopback:8000.
  • Valid plan sends 15 target requests and creates 17 CSV rows in additional transaction mode.
  • Parent mode changes CSV schema, not target traffic.
  • Search loop count and While poll count match predictions.
  • Only standard checkout branch executes in the valid plan.
  • Upsell executes once total; it is not interpreted as an RPS setting.
  • Broken While reproduction is hard-bounded and preserved before repair.
  • Timers/assertions/processors are reviewed for inherited controller scope.

15. Validity statement

Example: “Using Apache JMeter 5.6.3 and Java 17 against a loopback-only synthetic service, the controller tree produced the predicted browse/search/poll/checkout branch counts: 15 real target requests across two outer iterations, while additional-mode Transaction Controller produced two extra Journey Transaction JTL rows. Parent mode preserved target traffic but reduced CSV JTL to parent transaction rows. A deliberately misplaced Poll extractor kept the While condition true and increased Poll traffic until a four-second safety duration stopped the reproduction; restoring Post-Processor scope returned the journey to its predicted counts. These results validate controller and reporting semantics, not production capacity or distributed-global controller state.”

16. Cleanup

  1. Stop the local fixture.
  2. Preserve valid, parent, broken, and repaired evidence until review is complete.
  3. Remove debug listeners and synthetic variable dumps from later load plans.
  4. Restore all failure-reproduction hard bounds/configuration to the valid baseline.
  5. No production target, credential, certificate, RMI engine, paid service, container, database, or system-wide JVM/OS setting was changed.

17. What Chapter 12 adds to the operating model

The performance-testing operating model now has a control-flow contract: outer iteration count, nested loop multiplication, branch conditions and populations, Switch mapping, While termination state/safety bound, Transaction reporting mode, branch-execution controller semantics, scope inheritance, predicted target requests, and expected JTL labels are reviewed before execution.

Chapter 13 moves naturally to Recording Web Traffic, HTTP(S) Test Script Recorder, and Certificate Setup. Recording can create a raw request sequence, but the controller skills from this chapter are what turn that recording into a maintainable business journey instead of replaying every captured request flatly.

Knowledge check

What two numbers must be predicted separately when a Transaction Controller wraps the journey?

Why does parent mode not reduce actual target traffic?

What caused the broken Poll loop?

Why is Thread Group duration not considered the repair?

How does Chapter 12 prepare for recorded traffic in Chapter 13?

Next chapter

Recording Web Traffic, HTTP(S) Test Script Recorder, and Certificate Setup

Chapter 13 captures local HTTP(S) interactions safely, then applies controller/correlation/data principles so recordings become maintainable test plans rather than opaque replay scripts.

Official references and version notes

Version and compatibility note

Version-sensitive behavior was checked 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+. Simple Controller is organizational only. Loop Controller multiplies its loop count by the enclosing Thread Group iterations and exposes an index variable named __jm__<controller-name>__idx. If Controller should normally use Interpret Condition as Variable Expression with a boolean variable or __jexl3/__groovy; JavaScript condition mode has a potentially large performance penalty. While Controller evaluates its condition before and after its children, so non-idempotent functions such as counters in the condition can produce surprising behavior. Switch Controller selects one child by numeric index or name and has explicit fallback semantics. Throughput Controller is intentionally documented as badly named: it controls branch execution count/percentage, not request throughput; use a throughput Timer for rate control. Transaction Controller creates an additional transaction SampleResult unless Generate Parent Sample is enabled. In parent mode, child samples do not appear as separate CSV JTL rows. By default transaction elapsed excludes timers and pre/post-processor processing; the optional include-duration setting changes that measurement.

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.