Chapter 18Lesson 05~245 minutes

Checkpoint Lab — File Uploads, Downloads, Multipart Requests, and Large Payloads

The checkpoint has two purposes: validate a realistic lean transfer workflow and prove experimentally that result retention itself can become a measurable generator cost. The inefficient configuration is intentionally tiny and is preserved as evidence rather than hidden.

CheckpointMultipartMD5XML response retentionStorage cleanup

Learning objectives

  • Upload/download/delete deterministic small and medium synthetic files.
  • Quantify client bytes sent/received, exact server payload bytes, and server storage peak.
  • Predict sequential versus bounded concurrent storage/transfer state.
  • Enable one deliberately inefficient full-body XML JTL for a single medium download.
  • Compare JTL size/generator state while holding server payload constant.
  • Restore lean CSV/MD5 settings and verify zero target leftovers.

1. Exact assumptions and ceilings

Item Checkpoint baseline
JMeter Apache JMeter 5.6.3.
Java Java 17 JDK; JMeter 5.6.3 requires Java 8+.
Plugins None.
Fixture prompt18-upload-download-fixture-v1, Python standard library.
Target http://127.0.0.1:8018 only.
Files 64 KiB and 512 KiB deterministic ASCII only.
Server hard limits 1 MiB file; 2 MiB multipart request body.
Lean profile max 2 threads ×2 journeys; CSV JTL; MD5 download mode.
Inefficient profile 1 thread ×1 512 KiB download; XML JTL; response_data=true; MD5 off.
Timeouts Connect 500 ms; response 3000 ms.
Cleanup DELETE every UPLOAD_ID; final /stats zero stored uploads/bytes.
Containers/CI Not required.
Abort: non-loopback target, file outside generated manifest, >1 MiB file, >2 threads, >2 journeys/thread, falling free disk toward your local safety threshold, unexpected server storage growth, hash mismatch, repeated 4xx/5xx, or generator CPU/GC/disk saturation.

2. Setup and authorization/preflight

  1. Run generate_payloads.py; archive manifest/CSV output.
  2. Start fixture on 127.0.0.1:8018 with exact lab-storage root.
  3. GET /health and /stats; require stored=0.
  4. Record JMeter/Java/Python versions, generator free disk, payload directory bytes, result directory bytes.
  5. Confirm JMX uses only manifest paths and no sensitive files.

3. Lean checkpoint tree

Test Plan
├── User Defined Variables -> RUN_ID=${__P(RUN_ID,prompt18-checkpoint)}
├── HTTP Request Defaults -> 127.0.0.1:8018
├── CSV Data Set Config -> data/payloads.csv
└── Thread Group — 2 threads × 2 loops max
    ├── Upload Payload
    │   POST /upload
    │   fields: run_id, payload_name
    │   file: ${payload_path}, parameter=file, MIME=${mime_type}
    │   ├── extract UPLOAD_ID, SERVER_BYTES, SERVER_SHA256, SERVER_MD5
    │   └── assert against expected_bytes/hash variables
    ├── Download Payload
    │   GET /download/${UPLOAD_ID}
    │   Save response as MD5 hash=true
    │   └── assert body == ${expected_md5}
    └── Delete Upload
        DELETE /upload/${UPLOAD_ID}
        └── assert 204

4. Predictions before lean execution

Prediction A — bytes: each upload's JTL sentBytes will exceed raw expected_bytes because HTTP/multipart adds envelope bytes. Download network traffic remains the full payload even though the SampleResult retains only an MD5 string.

Prediction B — storage: target storage rises after upload and returns after delete. With two concurrent threads, peak storage may contain up to roughly two in-flight payloads, but final stored bytes must be zero.

Prediction C — size scaling: medium transfers should generally send/receive more bytes and often take longer than small transfers; the exact latency ratio is not assumed because loopback/cache/server overhead is nonlinear.

5. Run the lean profile

jmeter.bat -n `
  -t plans\checkpoint-transfer-lean.jmx `
  -l results\lean\results.jtl `
  -j results\lean\jmeter.log `
  -JRUN_ID=prompt18-checkpoint `
  -Jsample_variables=payload_name,expected_bytes

Record generator CPU/RSS/heap if practical, free disk before/after, JTL size, and fixture process/storage state.

6. Verify lean profile independently

python tools/analyze_transfer_jtl.py results/lean/results.jtl
python tools/analyze_server_events.py results/lean/server-events.jsonl
python tools/disk_snapshot.py . data results lab-storage
curl --fail --silent http://127.0.0.1:8018/stats

Require zero unexpected JTL failures, correct server hash/bytes assertions, upload/download/delete operation counts consistent with completed journeys, final stored_uploads=0/stored_bytes=0, and generator headroom.

7. Prepare the deliberately inefficient retention run

Use a separate tiny plan with exactly one 512 KiB upload → download → delete. Change the download sampler:

  • Save response as MD5 hash = false;
  • no View Results Tree;
  • same server/payload/asserted upload metadata;
  • 1 thread ×1 journey only.

For the -l result listener, use XML output and enable response data:

jmeter.bat -n `
  -t plans\checkpoint-transfer-retained-body.jmx `
  -l results\retained-body\results.jtl `
  -j results\retained-body\jmeter.log `
  -JRUN_ID=prompt18-retained `
  -Jjmeter.save.saveservice.output_format=xml `
  -Jjmeter.save.saveservice.response_data=true `
  -Jjmeter.save.saveservice.response_data.on_error=false
This pattern exists only to observe cost. Do not scale it beyond one medium download. XML full-body retention is not the load baseline.

8. Predictions before the inefficient run

Prediction D — artifact: the XML JTL will be much larger than a lean CSV file for one comparable transfer because it contains the entire 512 KiB text response plus XML/sample metadata.

Prediction E — target: server download payload size and service work should remain broadly comparable to a lean 512 KiB download; the major new cost is on JMeter/result serialization/storage.

Prediction F — memory/disk: generator result-disk activity and retained SampleResult/JTL body state increase. If the run is long enough to sample with jcmd, heap evidence may show additional retained data; regardless, JTL file size is direct proof of storage amplification.

9. Quantify retention overhead

Record:

python tools/disk_snapshot.py .   results/lean/results.jtl   results/retained-body/results.jtl   lab-storage

Compare:

  • lean CSV JTL bytes on disk;
  • retained-body XML JTL bytes on disk;
  • server download payload_bytes/service_wall_ms;
  • JMeter elapsed and generator state;
  • final server storage state.

Do not expect exact equality between JTL file-size delta and 524,288 bytes because XML escaping/metadata/other sample results add overhead.

10. Restore the lean configuration

Restore:

  • CSV JTL;
  • response_data=false;
  • Download Save response as MD5 hash=true;
  • original bounded thread/loop limits.

Rerun one medium journey as results/restored/... and verify the small result artifact plus identical server file hash/size behavior.

11. Quantify network and generator overhead correctly

Evidence Meaning
Manifest expected_bytes Exact raw payload content size.
Upload server request_content_length Exact multipart HTTP body size as received by fixture.
JTL sentBytes JMeter's bytes sent for the sample, including more HTTP protocol overhead.
Download server payload_bytes Exact file bytes streamed by the fixture.
JTL bytes JMeter sample received-byte counter; includes sample/protocol accounting, not a replacement for manifest.
JTL file bytes on disk Result-retention cost, not network payload.
Generator disk/heap/CPU Injector capacity/validity evidence.

12. Required evidence packet

Artifact Required content
Payload manifest 64/512 KiB paths, SHA-256, MD5.
Fixture topology/version 127.0.0.1:8018, guarded storage root, hard limits.
JMX/settings Multipart fields, MD5 mode, threads/loops, timeouts, result policy.
Lean results CSV JTL + jmeter.log + bytes/sentBytes percentiles/counts.
Server evidence request body/payload bytes, service time, peak/final storage, upload/download/delete counts.
Generator evidence free disk before/after, JTL sizes, CPU/RSS/heap sample when available.
Inefficient run 1×1 medium XML JTL with response_data=true preserved separately.
Restored run CSV + MD5 lean result proving original behavior.
Cleanup /stats zero uploads/bytes; guarded directories only.
Validity statement No production/storage capacity claim from tiny loopback results.

13. Validity statement

Example: “Using Apache JMeter 5.6.3/Java 17 against prompt18-upload-download-fixture-v1 on 127.0.0.1:8018, the checkpoint transferred deterministic 64 KiB and 512 KiB synthetic files. Multipart upload metadata matched the pre-generated byte counts/SHA-256/MD5, and JTL sentBytes exceeded raw file bytes as expected from multipart/HTTP overhead. Downloads transferred the full payload while the lean plan retained only JMeter's 32-character MD5 response representation. Per-upload DELETE returned server storage to zero. A separate 1-thread ×1-medium experiment disabled MD5 retention and stored response data in XML JTL, producing a materially larger result artifact without changing the server payload size; restoring CSV + response_data=false + MD5 returned the lean result profile. Generator disk/resource and server event evidence were reviewed before interpretation. This validates local payload, multipart, retention, and cleanup mechanics—not production network/object-storage capacity.”

14. Verification checklist

  • Only generated synthetic manifest files are uploaded.
  • Target is exactly 127.0.0.1:8018.
  • Files are 64 KiB/512 KiB and below 1 MiB hard limit.
  • Upload bytes/hashes match manifest.
  • Download MD5 matches manifest in lean profile.
  • Lean CSV JTL keeps bytes/sentBytes and no full bodies.
  • Inefficient XML/body run is exactly one medium journey and preserved separately.
  • Restored profile returns to CSV + MD5.
  • Final /stats shows zero stored uploads/bytes.
  • Generator headroom/result disk size are recorded before any capacity statement.

15. Cleanup / rollback

  1. Verify /stats is zero before stopping the fixture.
  2. Stop JMeter and the localhost fixture.
  3. Retain JTL/jmeter.log/manifest/server-event evidence until review completes.
  4. Only after review, remove data/payloads, lab-storage, and results from this lab root.
  5. Before any recursive manual deletion, print/resolve the path and require the exact expected directory name; never use a data-driven arbitrary path.
  6. No production file/object store, real document, credential, plugin, container, remote engine, paid service, OS/JVM global tuning, or uncontrolled endpoint was modified.

16. What Chapter 18 adds to the operating model

The performance-testing operating model now has a payload/storage contract: synthetic payload provenance, size distribution/hash manifest, immutable/unique file ownership, multipart/raw-body semantics, configured/achieved bytes and transfer counts, JMeter response-retention mode, JTL byte/artifact policy, generator disk/heap/CPU/network budget, server storage/hash/processing telemetry, guarded cleanup root, and explicit distinction between network/server/storage versus injector/result overhead.

Chapter 19 moves to Scripting with JSR223 and Groovy for Advanced Test Logic. That chapter introduces a controlled scripting escape hatch for transformations/validation that genuinely cannot be expressed cleanly with built-in components, while measuring scripting/cache/generator CPU cost and preserving thread-safe variable ownership.

Knowledge check

Why does the inefficient XML run stay at one medium download?

What should stay similar between lean and retained-body server evidence?

Why is JTL file size not a network-byte metric?

What must happen before manual recursive cleanup?

What is the Chapter 19 bridge?

Next chapter

Scripting with JSR223 and Groovy for Advanced Test Logic

Chapter 19 teaches small, cached, testable Groovy helpers while preferring declarative JMeter components whenever possible.

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+. For HTTP Request, supplying a File Path causes JMeter to send the request as multipart form data; the file entry also accepts a parameter name and MIME type. “Browser-compatible headers” suppresses per-part Content-Type and Content-Transfer-Encoding headers, leaving Content-Disposition. “Save response as MD5 hash” does not retain the original response in the SampleResult; instead JMeter stores a 32-character MD5 hash and explicitly documents this mode for testing large amounts of data. JMeter 5.6.3 allows ${...} expressions in the “store as MD5” checkbox. Default CSV result settings retain bytes and sentBytes but do not retain response data, sampler data, request headers, or response headers. CSV cannot store response data; demonstrating full-body JTL retention therefore requires a deliberately tiny XML-result run. The HTTP property httpsampler.max_bytes_to_store_per_request defaults to 0 (no truncation), so this chapter uses MD5 mode and lean result retention rather than increasing heap or globally truncating data as a troubleshooting shortcut.

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.