Chapter 20Lesson 05~255 minutes

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.

CheckpointTwo cwd runsPath repairDuplication reductionRuntime equivalence

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.
Abort: non-loopback resolved target, >2 threads, >3 work loops, fragment loaded from an unexpected path, missing/duplicate SESSION_ID, target scope mismatch, active sessions after a run, unexpected random input, repeated include errors, or generator saturation.

2. Setup and authorization/preflight

  1. Create the exact project tree from Lesson 2.
  2. Start fixture at 127.0.0.1:8020 with a fresh event log.
  3. GET /health//stats; require active_sessions=0.
  4. Record JMeter/Java versions and hash/list the main JMX, external fragment and property file.
  5. Confirm local.properties resolves 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:

  • cwd differs;
  • project_root identifies the same project;
  • jmx resolves to main-include.jmx;
  • property_file resolves to the same local.properties;
  • include_prefix resolves 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.log include/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;
  • __threadNum is 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

Example: “Apache JMeter 5.6.3/Java 17 executed a modular localhost plan against 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

  1. Verify fixture /stats reports zero active sessions.
  2. Stop JMeter runs and the localhost fixture.
  3. Keep JTL/jmeter.log/command manifests/property/module/event evidence until review completes.
  4. Delete only the disposable local results directory after review.
  5. 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?

What independently proves cwd portability?

Why is the broken no-prefix run valuable?

What failure would make a modular latency comparison invalid?

What is Chapter 21's bridge?

Next chapter

CLI Mode, Headless Execution, Result Files, and Reproducible Runs

Chapter 21 turns the launcher/result conventions into a rigorous command-line execution and evidence workflow.

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

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