Checkpoint Lab — Functions, Custom Properties, Reusable Fragments, and Modular Plans
The checkpoint is successful only if modularization reduces maintained definitions while preserving runtime behavior. You will prove the same session/work/cleanup sequence with Module and Include variants, prove the Include plan is independent of caller cwd through a launcher, preserve one intentional path-resolution failure, and show that all mutable user state remains thread-local.
Learning objectives
- Build the local fixture/project tree and verify tool/property/module assumptions.
- Refactor duplicated bootstrap definitions into a same-plan Module and external Include variant.
- Predict definition/runtime/path changes before executing them.
- Run the Include variant reproducibly from two working directories.
- Break and repair one Include path-resolution case while preserving the failure log.
- Produce a project/module/property/path/workload evidence packet and cleanup proof.
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:8020 only. |
| Fixture |
Python stdlib prompt20-modular-fixture-v1.
|
| Threads | 2 maximum. |
| Work loops | 3 per thread. |
| Pacing | 25 ms Constant Timer. |
| Session lifecycle | 1 create → 3 work → 1 delete per thread. |
| Properties |
config/local.properties via -q;
RUN_ID/VARIANT/include prefix via -J.
|
| Module variant | same-JMX Test Fragment + Module Controller. |
| Include variant |
external session-bootstrap.jmx + Include
Controller.
|
| Path contract | launcher resolves absolute project root and include prefix. |
| Results | Lean JTL + matching jmeter.log + command manifest + target JSONL. |
2. Setup and authorization/preflight
- Create the exact project tree from Lesson 2.
- Start fixture at 127.0.0.1:8020 with a fresh event log.
-
GET
/health//stats; require active_sessions=0. - Record JMeter/Java versions and hash/list the main JMX, external fragment and property file.
-
Confirm
local.propertiesresolves only loopback and conservative limits.
3. Before/after definition inventory
Before: two scenario branches each own the four-element session bootstrap definition = eight maintained setup definitions.
After Module: one four-element Test Fragment definition + lightweight same-plan Module references.
After Include: one four-element external Test Fragment definition + Include references in top-level plans.
The expected runtime operation count does not change: one session create per thread.
4. Predictions before changes
Prediction A — definition count: modularization reduces duplicate setup definitions by roughly half in the two-scenario example, but does not reduce runtime setup invocations.
Prediction B — user state: each of two threads
receives its own extracted SESSION_ID; work events
never use the other thread's session.
Prediction C — cwd: the two Include launcher runs
will record different caller cwd but identical resolved
project root/fragment prefix and equivalent target event counts.
Prediction D — broken path: bypassing the launcher without prefix will fail before a valid session/work sequence reaches the target; fixing only the prefix restores behavior.
5. Prove the Module variant first
Set-Location "F:\Labs\p20-modular-lab"
.\tools\run-local.ps1 -Variant module -RunId p20-module
Require two session creates, six work requests, two deletes, zero
active sessions, no JTL failure, and target session/thread mapping
consistent with user-1/user-2.
6. Include run from project root
Set-Location "F:\Labs\p20-modular-lab"
.\tools\run-local.ps1 -Variant include -RunId p20-root
Preserve results/p20-root/command-manifest.json, JTL,
jmeter.log and matching target events.
7. Include run from unrelated working directory
Set-Location "$env:TEMP"
& "F:\Labs\p20-modular-lab\tools\run-local.ps1" `
-Variant include `
-RunId p20-temp
Require the same target/sample semantics despite a different caller cwd.
8. Compare command/path manifests
python tools/check_manifests.py results/p20-root/command-manifest.json results/p20-temp/command-manifest.json
Verify:
cwddiffers;project_rootidentifies the same project;jmxresolves tomain-include.jmx;-
property_fileresolves to the same local.properties; -
include_prefixresolves to the same fragments directory; - results/logs remain run-scoped.
9. Verify target behavior independently
python tools/analyze_events.py results/server-events.jsonl
For each completed run, verify two session creates, six work events, two deletes, zero undeleted sessions and only successful statuses. If the event log combines runs, group by RUN_ID/VARIANT rather than relying only on totals.
10. Run the intentional path failure
From $env:TEMP, bypass the launcher as shown in Lesson
4 and omit includecontroller.prefix. Use a unique
RUN_ID and separate result/log directory.
Preserve:
- exact direct CLI command;
- caller cwd;
-
failed
jmeter.loginclude/file-resolution evidence; - any JTL created;
- fixture events showing no valid modular session/work sequence.
The broken run is diagnostic evidence; do not overwrite it.
11. Repair only the failing layer
Rerun through:
& "F:\Labs\p20-modular-lab\tools\run-local.ps1" `
-Variant include `
-RunId p20-repaired
The launcher adds the resolved absolute
includecontroller.prefix. No target, fragment content,
threads, loops, pacing, assertions or JVM settings need to change.
12. Property/function proof
Evidence must include the property file plus resolved values:
# Prompt 20 mandatory localhost environment
target.host=127.0.0.1
target.port=8020
threads=2
loops=3
pacing.ms=25
connect.timeout.ms=500
response.timeout.ms=2000
Record that:
-
Thread Group threads resolves from
__P(threads,1)to 2; -
Loop Controller loops resolves from
__P(loops,1)to 3; - target host/port resolves to 127.0.0.1:8020;
- RUN_ID/VARIANT are immutable per run;
-
__threadNumis evaluated in session sampler fields, not UDV configuration.
13. Thread/session isolation proof
For each run, pair:
- session-create event user-1 → one SESSION_ID;
- three work events for thread T1 using exactly that SESSION_ID;
- delete of that SESSION_ID;
- same independent sequence for user-2/T2.
No __setProperty/global mutable SESSION_ID is allowed.
14. Generator/measurement validity
Record generator CPU/memory during at least one successful run and
verify it has headroom. Compare target
service_wall_ms across Module/Include runs. The
workload is tiny, so the objective is structural reproducibility—not
a capacity number.
Configured load is 2 users ×3 work loops. Achieved work is six successful work events. If either count differs, modular/runtime/path resolution must be investigated before any latency comparison.
15. Required evidence packet
| Artifact | Required content |
|---|---|
| Project tree | plans/fragments/config/tools/results relationships. |
| JMX/module graph | Module same-plan target; Include external session-bootstrap relationship. |
| Property file | localhost host/port + conservative threads/loops/pacing/timeouts. |
| Function examples | __P, __threadNum, __property inspection; random strategy note. |
| Resolved paths | two command manifests with cwd/project root/include prefix/JMX/property file. |
| Two-run manifest | p20-root and p20-temp commands/results. |
| Failure log | intentional no-prefix Include failure preserved. |
| Repair evidence | launcher/prefix-only correction and successful smallest rerun. |
| Target evidence | session/work/delete counts and per-thread SESSION_ID ownership. |
| Duplication note | eight duplicated definitions → one four-element definition + references. |
| Validity | configured 6 work requests vs achieved 6; generator headroom; no production-capacity claim. |
16. Validity statement
prompt20-modular-fixture-v1 on 127.0.0.1:8020. Stable
target/load values came from config/local.properties,
while run identity and absolute Include prefix were supplied with
-J. The same session bootstrap was first referenced by
Module Controller in one JMX and then externalized to
session-bootstrap.jmx for Include Controller. Two
launcher runs from different caller working directories produced
different cwd manifests but the same resolved project root/prefix
and the same two-session/six-work/two-delete target behavior with
zero session leftovers. A direct no-prefix Include run was preserved
as a path-resolution failure; rerunning through the launcher fixed
only the include prefix and restored behavior. Per-user SESSION_ID
remained thread-local. This proves project/path/modular
reproducibility for the bounded local experiment; it does not
establish production service capacity.”
17. Verification checklist
- Only target 127.0.0.1:8020.
- JMeter 5.6.3 / Java 17 / no plugin assumptions recorded.
- Property file values resolve to 2 threads, 3 work loops, 25 ms pacing.
- Module reference target name is unique.
-
Include filename is plain
session-bootstrap.jmx; launcher supplies prefix. - Root-cwd and temp-cwd Include runs both succeed.
- Broken no-prefix log is preserved and repaired without workload/target changes.
- Each thread owns one SESSION_ID and performs three work requests.
- Final target stats show zero active sessions.
- Configured and achieved work counts equal six for each valid run.
18. Cleanup / rollback
-
Verify fixture
/statsreports zero active sessions. - Stop JMeter runs and the localhost fixture.
-
Keep JTL/
jmeter.log/command manifests/property/module/event evidence until review completes. -
Delete only the disposable local
resultsdirectory after review. - No public/production API, credential, recorder certificate, remote engine, container, database/message service, paid platform, CI secret, OS/JVM global tuning or uncontrolled file path was changed.
19. What Chapter 20 adds to the operating model
The production performance-testing operating model now has a modularity and configuration contract: every plan declares property sources/defaults, thread-local versus process-global state, Test Fragment inputs/outputs, Module/Include dependency graph, unique names, include/file path resolution, project-root launcher behavior, synthetic data/reproducibility strategy, command manifest, configured-versus-achieved workload, generator headroom, target-equivalence evidence and cleanup before modular results are accepted.
Chapter 21 moves to CLI Mode, Headless Execution, Result Files, and Reproducible Runs. It takes the project launcher/property/path discipline from this chapter and makes the command/result contract itself the primary subject.
Knowledge check
What must remain unchanged when refactoring duplicate setup into fragments?
The runtime workload/session order and target operations; only definition organization should change.
What independently proves cwd portability?
Two command manifests show different caller cwd values while resolved project/module paths and target behavior remain equivalent.
Why is the broken no-prefix run valuable?
It proves the evidence path can identify a filesystem/module-resolution failure before target traffic and validates the launcher repair.
What failure would make a modular latency comparison invalid?
Different configured/achieved sample counts, session ownership, target event distribution, or generator saturation between variants.
What is Chapter 21's bridge?
Formalize the CLI/property/result-file command contract so headless runs are reproducible beyond the modularity-specific launcher.
Official references and version notes
- JMeter Component Reference — Module Controller — runtime substitution of an already loaded controller/fragment and unique fragment naming.
-
JMeter Component Reference — Include Controller
— external JMX/Test Fragment use, filename limitations,
includecontroller.prefix, and path fallback behavior. - JMeter Component Reference — Test Fragment — reusable fragment semantics with Module/Include Controllers.
- JMeter Functions — __P — simplified command-line property lookup and default behavior.
- JMeter Functions — __property — general JMeter property lookup and optional variable assignment.
- JMeter Functions — __threadNum — thread-group-local thread numbering and Configuration Element restrictions.
- JMeter Functions — __Random — pseudo-random values and optional variable assignment.
- JMeter Component Reference — Random Variable — seeded/per-thread reproducible random-number option.
-
JMeter Getting Started
—
-q/-J, property files, and JMeter configuration loading. - JMeter Best Practices — GUI authoring/debugging and non-GUI execution for load.
- Apache JMeter downloads — current stable release and Java requirement.
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+. A Module Controller substitutes an
already loaded controller/fragment into the active runtime path;
fragments referenced by Module Controller need unique names
because JMeter uses the controller/parent name path to find them
after reload. Include Controller is for external JMX/Test Fragment
content. Its Filename field does not support
variables/functions. The
includecontroller.prefix property can prefix the
filename; if prefix+filename cannot be found, JMeter attempts the
filename relative to the JMX launch directory. Top-level Cookie
Manager/User Defined Variables belong in the main test plan rather
than an included JMX because included copies are not guaranteed to
work as expected. __P(name,default) is intended for
command-line properties; without an explicit default it returns
1. __threadNum is local to its Thread
Group and should not be placed in Configuration Elements such as
User Defined Variables because those are processed by a separate
thread. For reproducible random numeric data, the Random Variable
Config Element exposes a seed/per-thread option; the simple
__Random function does not expose an equivalent seed
parameter.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.