Chapter 01Lesson 05~130 minutes

Checkpoint Lab — Performance Testing Foundations: Load, Stress, Spike, Soak, and Capacity

Complete the chapter with one evidence-driven performance experiment against a disposable local service. The goal is not a large load number; it is a defensible chain from question and authorization to observed samples, generator/target state, and an explicit validity limit.

CheckpointCharterCLIEvidence packetValidity note

Learning objectives

  • Create a concrete performance-test charter with hypotheses, acceptance criteria, ceilings, and stop conditions.
  • Predict workload, target, result, and generator changes before execution.
  • Execute one deliberately small loopback baseline with JMeter 5.6.3 in CLI mode.
  • Verify sample count, failures, elapsed-time percentiles, approximate throughput, fixture counters, and generator health.
  • Preserve an evidence packet that supports independent review.
  • Write a validity note that states both what the run demonstrates and what it cannot demonstrate.

1. Scenario: a local synthetic work endpoint

Use the same fixture_server.py from Lesson 2. Start from a fresh fixture process so its request counter begins at zero. The checkpoint plan requests /work?delay_ms=60 with two threads and ten loops per thread, for a maximum of 20 samples. This is deliberately tiny: the learning objective is experimental discipline, not stress.

Do not enlarge the load. The checkpoint is complete when you can explain and verify 20 bounded local samples. More traffic would not add useful evidence for the chapter objective.

2. Exact assumptions

Item Checkpoint baseline
JMeter Apache JMeter 5.6.3.
Java Java 17 local lab runtime; JMeter 5.6.3 itself supports Java 8+.
Plugins None.
Target 127.0.0.1:8000 only.
Fixture Python standard-library ThreadingHTTPServer from Lesson 2.
Configured work 2 threads, 2-second ramp, 10 loops each, one sampler = at most 20 samples.
Request GET /work?delay_ms=60.
Timeouts 1 s connect, 2 s response.
Evidence JMX, CLI command, JTL, jmeter.log, fixture /stats, Java/JMeter versions, generator resource snapshot, validity note.

3. Write the charter before execution

Charter field Checkpoint statement
Business question Can this disposable fixture complete a tiny concurrent baseline correctly while producing reproducible client/server evidence?
Hypothesis With two threads and 60 ms synthetic service delay, 20 samples should complete with zero failed samples; elapsed time should cluster near or above the injected delay, with ordinary local scheduling variation.
Acceptance 20 recorded samples, zero failed samples, fixture total = 20 from a fresh process, no unsafe injector pressure.
Stop conditions Target not loopback; unexpected errors; fixture health fails; workstation becomes unstable; any unplanned workload change.
Non-goal Do not estimate production capacity, production SLO compliance, or a maximum sustainable request rate.

4. Predict state changes before the run

  1. Workload state: two JMeter threads will each execute ten iterations, so 20 sampler attempts are expected.
  2. Target state: the fresh fixture's total counter should move from 0 to 20 if all requests reach it.
  3. Result state: the JTL should contain 20 sample rows; each successful row should report an elapsed time that includes the synthetic delay and client/server overhead.
  4. Generator state: Java/JMeter will briefly consume CPU, memory, sockets, and disk for results; this tiny run should not create material sustained pressure.

These predictions make the run falsifiable. If any one is wrong, investigate rather than rewriting the story after the fact.

5. Preflight and authorization checklist

  • Fixture process prints fixture=http://127.0.0.1:8000.
  • /health returns {"status":"ok"}.
  • /stats reports total: 0 from the fresh fixture.
  • jmeter -v and java -version outputs are captured.
  • JMX contains 127.0.0.1, port 8000, two threads, ten loops, and the bounded timeouts.
  • A unique empty result directory such as results/checkpoint-001 exists.
  • You know how to stop JMeter/fixture and will abort if the target or resource state differs from the charter.

6. Checkpoint JMX

Save this as chapter01-checkpoint.jmx. It is intentionally simple and plugin-free.

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan"
              testname="Chapter 01 Checkpoint Baseline" enabled="true">
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables"
                   elementType="Arguments"
                   guiclass="ArgumentsPanel"
                   testclass="Arguments"
                   testname="User Defined Variables">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup"
                   testname="Checkpoint Baseline — 2 users × 10 loops" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller"
                     elementType="LoopController"
                     guiclass="LoopControlPanel"
                     testclass="LoopController"
                     testname="Loop Controller">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">10</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">2</stringProp>
        <stringProp name="ThreadGroup.ramp_time">2</stringProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
        <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
      </ThreadGroup>
      <hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui"
                          testclass="HTTPSamplerProxy"
                          testname="GET /work" enabled="true">
          <elementProp name="HTTPsampler.Arguments"
                       elementType="Arguments"
                       guiclass="HTTPArgumentsPanel"
                       testclass="Arguments"
                       testname="User Defined Variables">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain">127.0.0.1</stringProp>
          <stringProp name="HTTPSampler.port">8000</stringProp>
          <stringProp name="HTTPSampler.protocol">http</stringProp>
          <stringProp name="HTTPSampler.path">/work?delay_ms=60</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <stringProp name="HTTPSampler.connect_timeout">1000</stringProp>
          <stringProp name="HTTPSampler.response_timeout">2000</stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

7. Execute once in CLI mode

mkdir -p results/checkpoint-001
jmeter -n -t chapter01-checkpoint.jmx   -l results/checkpoint-001/results.jtl   -j results/checkpoint-001/jmeter.log

PowerShell:

New-Item -ItemType Directory -Force results\checkpoint-001 | Out-Null
& "$env:JMETER_HOME\bin\jmeter.bat" -n `
  -t chapter01-checkpoint.jmx `
  -l results\checkpoint-001\results.jtl `
  -j results\checkpoint-001\jmeter.log

While it runs, observe generator CPU/memory and keep the fixture terminal visible. If the machine becomes unstable or any guard fails, stop rather than “pushing through.”

8. Verify independently

After completion, query target state:

curl --fail --silent http://127.0.0.1:8000/stats

Expected from a fresh fixture is a total of 20 requests. Then adapt the Lesson 2 analyzer path to results/checkpoint-001/results.jtl and record sample count, error count, p50, p95, and approximate samples/second. Treat the p95 as a description of this tiny sample set only.

Also inspect jmeter.log for unexpected errors. A successful process exit is not a substitute for checking sample correctness and the target counter.

9. Build the evidence packet

Artifact What it proves What it does not prove
chapter01-checkpoint.jmx Configured workload and target. That the workload was achieved exactly as intended.
CLI command/run record Exact execution inputs and artifact locations. Sample correctness.
results.jtl Recorded sample outcomes/timing fields. Root cause of any slowdown.
jmeter.log JMeter engine/runtime diagnostics. Server health by itself.
Fixture /stats Independent count of requests reaching the local service. A production business transaction count.
Generator resource snapshot Whether the injector obviously lacked headroom. Complete low-level performance diagnosis.
Version record Java/JMeter environment identity. Future compatibility with different releases.
Validity note Scope of the conclusion and known limitations. A replacement for raw evidence.

10. Write the validity note

A strong checkpoint note is explicit:

Example validity statement: “On 2026-09-04, using Apache JMeter 5.6.3 with Java 17 on this workstation, the loopback-only Chapter 01 fixture completed the configured 20-sample baseline with the recorded JTL/error/percentile values and fixture request count. The generator showed no obvious unsafe resource pressure during this tiny run. This demonstrates that the bounded local workflow and evidence path functioned under these conditions. It does not establish production capacity, production SLO compliance, long-duration stability, distributed scalability, or root cause for behavior in another environment.”

The sentence about what the run does not prove is part of professional performance engineering, not a disclaimer to hide weak results.

11. Cleanup and rollback

  1. Stop the fixture with Ctrl+C.
  2. Confirm no local fixture process remains listening on port 8000.
  3. Keep results/checkpoint-001 until review is complete.
  4. Do not delete the failed or surprising run if diagnosis is still open.
  5. No certificates, accounts, databases, remote engines, plugins, or system-wide settings were changed by this lab.

12. Checkpoint completion criteria

  • The target remained loopback-only and authorized.
  • The configured ceiling was not increased.
  • Predicted sample count and target counter were checked.
  • JTL and jmeter.log were preserved.
  • Generator health was observed rather than assumed.
  • Percentiles were reported with the tiny-sample limitation.
  • The validity note clearly separates evidence from unsupported capacity claims.

Knowledge check

Why must the checkpoint begin with a fresh fixture process?

If the JTL has 20 rows but the fixture reports 18 requests, is the checkpoint complete?

Can a zero-error 20-sample run prove production capacity?

Why record generator health in such a small lab?

What is the bridge from this chapter to Chapter 02?

Next chapter

JMeter Architecture, Java Setup, Installation, and First Test Plan

You now know what a performance experiment must prove. Chapter 02 turns that mental model into a reproducible JMeter runtime and explains the engine, GUI/CLI boundary, installation, and first authored plan.

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against current Apache JMeter primary documentation on 2026-09-04. The production download is Apache JMeter 5.6.3 and requires Java 8+. The mandatory Chapter 01 executable lab uses Java 17 as a pinned local lab choice, no third-party plugins, no distributed engines, and only the loopback target 127.0.0.1:8000. Apache guidance requires CLI mode for actual load execution; GUI mode is limited to construction and bounded debugging. The Open Model Thread Group is discussed conceptually only and remains marked experimental in the current Component Reference.

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.