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.
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. |
2. Setup and authorization/preflight
-
Run
generate_payloads.py; archive manifest/CSV output. -
Start fixture on 127.0.0.1:8018 with exact
lab-storageroot. -
GET
/healthand/stats; require stored=0. - Record JMeter/Java/Python versions, generator free disk, payload directory bytes, result directory bytes.
- 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
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
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
-
Verify
/statsis zero before stopping the fixture. - Stop JMeter and the localhost fixture.
-
Retain JTL/
jmeter.log/manifest/server-event evidence until review completes. -
Only after review, remove
data/payloads,lab-storage, andresultsfrom this lab root. - Before any recursive manual deletion, print/resolve the path and require the exact expected directory name; never use a data-driven arbitrary path.
- 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?
It intentionally demonstrates full-body retention cost without creating an unbounded disk/heap experiment.
What should stay similar between lean and retained-body server evidence?
The 512 KiB payload size and server-side download work; the major changed state is JMeter result retention.
Why is JTL file size not a network-byte metric?
It measures serialized result-artifact storage and can include metadata/body encoding independent of network payload size.
What must happen before manual recursive cleanup?
Resolve and verify the exact guarded lab path/name; never delete a path constructed from arbitrary test data.
What is the Chapter 19 bridge?
Use JSR223/Groovy only for logic that built-in components cannot express cleanly, and measure scripting/cache/thread-safety cost on the generator.
Official references and version notes
- JMeter Component Reference — HTTP Request — multipart/form-data, file path/parameter/MIME fields, browser-compatible headers, and Save response as MD5 hash.
- JMeter Component Reference — Save Responses to a file — response-to-disk behavior, filename prefix, numbering, and variable output.
-
JMeter Listeners / Result files
— CSV fields including bytes/sentBytes, listener memory guidance,
response-data retention, and CLI
-lbehavior. -
JMeter Properties Reference
— save-service defaults,
httpsampler.max_bytes_to_store_per_request, buffer sizing, and result retention settings. - JMeter 5.6.3 Changes — expression support for HTTP Request “store as MD5” and current release changes.
- JMeter Best Practices — GUI for authoring/debug and CLI mode for meaningful 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+. 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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.