Chapter 32Lesson 05~330 minutes

Checkpoint Lab — Plugins, Custom Components, JMeter APIs, and Extension Strategy

The checkpoint treats a JMeter extension as a small software product. The expected result is not merely “the sampler appears in a menu.” You must prove provenance/hash, Java/JMeter compatibility, unit tests, JMX dependency resolution, bounded runtime behavior, generator/target validity and a rollback path.

CheckpointCompatibility lockJAR hashUnit testsUpgrade rollback

Learning objectives

  • Complete the chapter checkpoint for Plugins, Custom Components, JMeter APIs, and Extension Strategy as one reviewable, bounded experiment.
  • State the workload, predictions, acceptance criteria, authorization boundary, and abort conditions before execution.
  • Reconcile configured versus achieved work with JTL, jmeter.log, target evidence, and generator validity before making a conclusion.
  • Produce an evidence packet that records the exact inputs, results, diagnosis or gate outcome, and any material limitations.
  • Perform cleanup or rollback and explain how the checkpoint evidence hands off to the next chapter or operating practice.

1. Exact assumptions and ceilings

Item Checkpoint baseline
JMeter/Java Apache JMeter5.6.3 / Java17.
Third-party plugins None required/installed by the mandatory path.
Custom extension p32-safeid-sampler 1.0.0 built from shown source.
API boundary AbstractJavaSamplerClient + JavaSamplerContext + SampleResult.
Activation Project-local extensions/ through search_paths.
Target 127.0.0.1:8032 only.
Workload 2 threads ×5 loops; 10 Java samples +10 HTTP samples =20 JTL rows.
Target ceiling 10 HTTP requests.
Pacing 150 ms on target HTTP request.
Evidence inventory, JAR/source hashes, compatibility report, unit test output, JMX dependency map, JTL/jmeter.log, target events/stats, rollback log.
Abort: non-loopback traffic, unexpected external/plugin JAR, Java/JMeter/hash mismatch, unresolved JMX class, duplicate active extension versions, classloading linkage error, >10 target requests, generator saturation, missing evidence or any attempt to “fix” startup by copying unpinned JARs.

2. Predictions before modification

P1: core-only JMeter startup/smoke works before and after the custom extension because the base installation is not modified.

P2: the extension-dependent JMX run without search_paths cannot load devops.academy.p32.SafeIdSampler; this failure proves the JMX has a real external/custom dependency.

P3: after building/locking the JAR and activating its exact extension path, the plan produces20 JTL samples and10 target requests.

P4: removing the extension path restores core-only operation without deleting/changing shared JMeter JARs.

3. Freeze the pre-change inventory

& "$env:JMETER_HOME\bin\jmeter.bat" -v
java -version

python .\tools\inventory_extensions.py `
  --jmeter-home $env:JMETER_HOME `
  --project-extensions .\extensions `
  --out .\results\inventory-before.json

Review every non-Apache JAR already present. If the base JMeter home is already polluted/unknown, use a clean JMeter5.6.3 distribution before continuing.

4. Compile and unit-test the extension

Use the exact source/commands from Lesson2. Require:

  • javac --release17 core/test PASS;
  • adapter compiles against ApacheJMeter_core.jar + ApacheJMeter_java.jar from this JMeter5.6.3 home;
  • versioned JAR p32-safeid-sampler-1.0.0.jar created in project extensions/.

5. Create and verify the compatibility lock

Run lock_extension.py then check_compatibility.py. Require exact JMeter5.6.3, Java17 and JAR SHA match. Retain compatibility JSON beside the test results.

6. Build the JMX dependency map

Save extension-demo.jmx using the Lesson2 tree and run map_jmx_dependencies.py. Require:

external_or_custom_classes:
  - devops.academy.p32.SafeIdSampler

locked_dependencies:
  - id: p32-safeid-sampler
    version: 1.0.0
    class: devops.academy.p32.SafeIdSampler

unresolved_classes: []
status: PASS

The actual JSON contains the generated JAR hash from the lock.

7. Target authorization and preflight

Start extension_target.py on 127.0.0.1:8032 with max10 and verify /health. Do not allow a target property outside loopback in this checkpoint. This is inherited directly from Chapter31's safe-load boundary.

8. Negative compatibility proof

Run the extension-dependent JMX once without the project search_paths. Preserve the failed JTL/jmeter.log. The expected problem is custom-class availability, not target behavior. The fixture should still show zero/near-zero HTTP target requests because the tree stops on the extension sampler error.

Do not “repair” this negative run by copying the JAR into shared lib/ext; the next step activates the exact locked project path.

9. Authorized compatibility run

$ExtPath = (Resolve-Path .\extensions).Path

& "$env:JMETER_HOME\bin\jmeter.bat" `
  "-Jsearch_paths=$ExtPath" `
  -n `
  -t .\plans\extension-demo.jmx `
  -q .\config\extension.properties `
  -l .\results\positive\results.jtl `
  -j .\results\positive\jmeter.log

Expected independent observations:

  • 20 JTL data samples: 10 SafeIdSampler +10 LocalTarget;
  • target /stats: requests10/successes10/rejections0;
  • no ClassNotFound/NoSuchMethodError in jmeter.log;
  • generator remains unsaturated; otherwise extension-overhead conclusions are invalid.

10. Evidence packet

Artifact Required
Core/plugin/custom inventory Before/after JSON with classification/path/hash/version manifest fields.
JAR/source lock extensions.lock.json with JMeter5.6.3/Java17/JAR SHA/source SHAs/public APIs.
Dependency source Chapter-local source for mandatory custom extension; no third-party plugin.
Unit tests SafeIdCoreTest PASS output.
Compatibility matrix JMeter/Java/hash PASS report.
Startup logs Core-only clean log, negative missing-extension log, positive extension log.
JMX dependency map Custom class resolved to exact locked JAR; no unresolved classes.
Runtime evidence 20 JTL rows + target10 events/stats + generator health.
Rollback plan No shared lib/ext mutation; remove search_paths/use previous locked extension directory.

11. Upgrade procedure

For a future 1.0.1 candidate:

  1. create a separate source/build directory and versioned JAR;
  2. review source/dependencies/API/deprecation warnings and maintainer notes if third-party;
  3. run pure unit tests;
  4. generate a candidate lock with new hash—do not overwrite the approved lock yet;
  5. verify JMeter5.6.3/Java17 compatibility in a clean/local environment;
  6. run core-only smoke, negative dependency check if useful, then the same 2×5 target-bounded plan;
  7. compare configured/achieved results and generator state;
  8. promote the candidate lock/JAR together only after PASS.

Never leave 1.0.0 and1.0.1 JARs containing the same class in the same active extension path.

12. Rollback procedure

Keep the prior approved lock/JAR in a separate inactive versioned directory. To roll back: stop JMeter/engines, point search_paths back to the prior directory, verify hashes/JMeter/Java on every engine/image, run core-only smoke and the bounded compatibility plan, then preserve the rollback report. Do not hot-swap JARs inside a running JMeter process.

13. Distributed/CI/container extension rule

If this plan later runs remotely, every engine must pass the same JMeter/Java/extension lock; the current remote manual already requires identical JMeter versions and recommends the same Java. In CI/container environments emit the inventory/compatibility report before load and pin the image/artifact containing the JAR. A controller-only PASS does not prove worker compatibility.

14. Cleanup

  1. Stop the localhost fixture and confirm port8032 closes.
  2. Keep evidence/lock/source until review.
  3. Deactivate the custom extension by omitting/removing the project search_paths; do not change shared JMeter home.
  4. Delete disposable build/ products only after the locked JAR/hash evidence is retained.
  5. No production/shared target, credential, RMI engine, plugin repository or system-wide Java/JMeter configuration was modified.

15. Production operating-model addition and Chapter33 bridge

Chapter32 adds an extension governance contract: core/external/custom inventory, exact JMeter/Java/API compatibility, JAR/source provenance and hashes, JMX dependency mapping, isolated classpath/dependency placement, unit/concurrency tests, generator-cost validation, consistent remote/CI/container inventories, staged upgrades and tested rollback are required before extension-dependent performance results are trusted.

Chapter33 moves to Troubleshooting Out-of-Memory, Socket, SSL, DNS, and Distributed Failures. The classpath and generator-state discipline learned here becomes part of that broader troubleshooting sequence: not every JVM/network/distributed failure is the SUT, and extension drift must be ruled out before deeper runtime tuning.

Knowledge check

Why keep old and new extension JARs in separate inactive/active paths?

What should the negative missing-extension run prove?

Why must remote engines share the extension lock?

If the positive run has20 JTL rows but target stats show7 requests, is it valid?

What Chapter33 failure class can extension drift resemble?

Next chapter

Troubleshooting Out-of-Memory, Socket, SSL, DNS, and Distributed Failures

Chapter33 expands preserve-first diagnosis across JVM memory, network, TLS/DNS and distributed-engine layers.

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against current primary/maintainer documentation on 2026-09-05. The mandatory runtime is Apache JMeter 5.6.3 with Java 17 and no third-party plugin. JMeter discovers JMeter component/plugin jars in JMETER_HOME/lib/ext; dependency/utility jars belong in JMETER_HOME/lib. Additional component/plugin paths can be provided with search_paths; utility/dependency paths use user.classpath or plugin_dependency_paths. The CLASSPATH environment variable does not affect normal JMeter startup because JMeter is launched with java -jar. Official Javadocs encourage custom Java samplers to extend AbstractJavaSamplerClient rather than implement JavaSamplerClient directly. JMeter creates a JavaSamplerClient instance per user/thread and calls setup/run/teardown around that thread's lifecycle. Functions differ: a function occurrence can be executed by multiple threads, so mutable non-thread-safe function state needs synchronization or thread-local design. Current JMeter best practices continue to prefer cached JSR223 Groovy over BeanShell for intensive scripting. The JMeter Plugins Manager is maintained by JMeter-Plugins.org, not by the Apache JMeter project; the mandatory lab intentionally installs none. If a team adopts it or any managed plugin, record the exact version, source and SHA-256 and review install/update changes before execution.

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.