Assignment · Batch 18 · Topic: Performance Testing
- 🎯 Overview
- 🗂️ Project Structure
- ⚙️ Prerequisites & Setup
- 🚀 Quick Start
- 📘 Task 1 — Daily Finance
- 📗 Task 2 — DemoQA BookStore
- 📊 Results at a Glance
- 🎥 Submission Artifacts
- 🧠 Key Design Notes
- 🛠️ Troubleshooting
Two independent k6 test scripts, each producing a self-contained HTML report on completion:
| # | Scenario | Focus | Load model |
|---|---|---|---|
| 1 | Daily Finance — admin authenticates, lists users, drills into one by ID | Functional correctness under load + per-endpoint thresholds | Constant 5 VUs · 30s |
| 2 | DemoQA BookStore — read the books catalogue | Response-time SLA under rising/peak/falling traffic | Staged ramp 0→10→25→0 VUs |
Both scripts share the same reporting pipeline: the k6-reporter library renders a rich HTML dashboard via handleSummary(), while a live console summary is printed on stdout.
K6Mastery/
├── task1-dailyfinance.js # Task 1 — login → users → user-by-id (tagged + thresholds)
├── task2-bookstore.js # Task 2 — ramping load against Books API
├── Reports/ # 📄 Auto-generated HTML reports (git-ignored)
│ ├── task1-dailyfinance-report.html
│ └── task2-bookstore-report.html
├── Screenshots/ # 🖼️ Report screenshots for submission
│ ├── task1-dailyfinance-report.png
│ └── task2-bookstore-report.png
├── .gitignore # Reports/ is excluded from version control
└── README.md
🔒
Reports/is git-ignored as required by the assignment — reports are build artifacts, regenerated on every run.
1. Install k6 (the only hard requirement — scripts pull the HTML reporter from a CDN at runtime, so you just need internet access):
# macOS
brew install k6
# Windows
choco install k6
# Linux (Debian/Ubuntu)
sudo gpg -k && sudo apt-get install k62. Verify the install:
k6 version # → k6 v2.1.0 (or newer)That's it — no npm install, no local dependencies. ✅
# 📘 Task 1 — Daily Finance (~30s)
k6 run task1-dailyfinance.js
# 📗 Task 2 — BookStore ramping load (~2 min)
k6 run task2-bookstore.jsEach run writes its report to Reports/…-report.html. Open it in any browser:
open Reports/task1-dailyfinance-report.html # macOS💡 First run tip: the
Reports/folder must exist before k6 can write to it. If you cloned this fresh, runmkdir -p Reportsonce.
An admin logs in, pulls the full user list, randomly picks a user, re-fetches that user by ID, and asserts the round-trip is consistent.
sequenceDiagram
autonumber
participant K6 as k6 · Admin VU
participant Auth as POST /auth/login
participant List as GET /user/users
participant One as GET /user/{id}
K6->>Auth: { email, password }
Auth-->>K6: 200 · { token }
Note over K6: extract JWT token
K6->>List: Authorization: Bearer «token»
List-->>K6: 200 · [ 900 users ]
Note over K6: pick a RANDOM user
K6->>One: Bearer «token» · /user/«_id»
One-->>K6: 200 · { user }
Note over K6: ✔ assert _id matches<br/>🖨 print id · name · email · phone
| Step | Method & Endpoint | k6 Tag |
|---|---|---|
| Login | POST /api/auth/login |
{ name: "Admin Login API" } |
| List users | GET /api/user/users |
{ name: "Get All Users API" } |
| User by ID | GET /api/user/{id} |
{ name: "Get User By ID API" } |
Base URL:
https://dailyfinanceapi.roadtocareer.net
- Login status is
200and a token is present - User list status is
200and the list is a non-empty array - User-by-ID status is
200 - 🎯 Selected user's
idmatches the searched user'sid(the core integrity check)
| Metric (by tag) | Threshold | Measured p(95) |
Result |
|---|---|---|---|
http_req_duration{name:Admin Login API} |
p(95) < 600ms |
190 ms | 🟢 Pass |
http_req_duration{name:Get All Users API} |
p(95) < 800ms |
477 ms | 🟢 Pass |
http_req_duration{name:Get User By ID API} |
p(95) < 600ms |
146 ms | 🟢 Pass |
checks (overall success rate) |
rate > 0.99 |
100% | 🟢 Pass |
🖨️ Sample console output (click to expand)
[Admin Login API] status=200 response time=112.86 ms
[Get All Users API] status=200 response time=277.94 ms (users=900)
[Get User By ID API] status=200 response time=65.14 ms
--> Selected User:
id : 2878f6fb-f31a-4886-9379-c5da46bc349c
name : Jovan Romaguera
email : Sylvia899@gmail.com
phoneNumber : 01575753529
✓ Login status is 200
✓ Token is present
✓ Get All Users status is 200
✓ User list is a non-empty array
✓ Get User By ID status is 200
✓ Selected user id matches searched user id
Simulates traffic gradually increasing → holding at peak → gradually decreasing, verifying the Books API stays responsive throughout.
xychart-beta
title "Ramping VU Load Profile (120s total)"
x-axis "Time (seconds)" [0, 20, 50, 70, 100, 120]
y-axis "Virtual Users" 0 --> 25
line [0, 10, 10, 25, 25, 0]
| Stage | Duration | Target VUs | Behaviour |
|---|---|---|---|
| 1 | 20s | 10 | 🔼 Ramp up |
| 2 | 30s | 10 | ➡️ Hold |
| 3 | 20s | 25 | 🔼 Ramp up to peak |
| 4 | 30s | 25 | ➡️ Hold at peak |
| 5 | 20s | 0 | 🔽 Ramp down |
Endpoint:
GET https://demoqa.com/BookStore/v1/Books
- Response status is
200 - Response body contains books (non-empty array)
- Response time is < 600ms (per-request check)
- 🖨️ Prints the total number of books returned (surfaced both to console and as a custom
books_returnedgauge in the report)
| Metric | Threshold | Measured | Result |
|---|---|---|---|
http_req_duration |
p(95) < 600ms |
563 ms | 🟢 Pass |
http_req_failed |
rate < 1% |
0.00% | 🟢 Pass |
📚 Total books returned: 8. Under peak load a handful of individual requests crossed the 600 ms mark (per-request checks landed at 99.7%, max 1.12s), yet the aggregate p(95) stayed under 600 ms — exactly the SLA the test is designed to guard.
🖨️ Sample console output (click to expand)
Total number of books returned from the API: 8
✓ status is 200
✓ body contains books
✗ response time < 600ms ↳ 99% — ✓ 1397 / ✗ 12
✓ http_req_duration...: p(95)=563.28ms (threshold p95<600 ✔)
✓ http_req_failed.....: 0.00% (threshold rate<0.01 ✔)
books_returned......: 8 min=8 max=8
| Task 1 · Daily Finance | Task 2 · BookStore | |
|---|---|---|
| Requests | 309 | 1,409 |
| Failed requests | 0 (0.00%) | 0 (0.00%) |
| Breached thresholds | 0 ✅ | 0 ✅ |
| Checks passed | 100% | 99.7% |
| Peak load | 5 VUs | 25 VUs |
| Slowest p95 | 477 ms | 563 ms |
| Verdict | 🟢 PASS | 🟢 PASS |
| Artifact | Location | Status |
|---|---|---|
| Task 1 HTML report | Reports/task1-dailyfinance-report.html |
✅ |
| Task 2 HTML report | Reports/task2-bookstore-report.html |
✅ |
| Task 1 report screenshot | Screenshots/task1-dailyfinance-report.png |
✅ |
| Task 2 report screenshot | Screenshots/task2-bookstore-report.png |
✅ |
| 🎬 Screen recording of both runs | record locally | ⬜ |
To record the run video (required for submission): start a screen recorder — on macOS, QuickTime → File → New Screen Recording — then run each command and let the report open:
k6 run task1-dailyfinance.js
k6 run task2-bookstore.jsThese are the deliberate decisions worth knowing before grading.
-
name&idfield mapping. The Daily Finance API returns_id,firstName, andlastName— there is no singlenameoridfield. The script therefore mapsid → _idand printsnameasfirstName + lastName, matching the assignment's intent. -
Tag names aligned to threshold selectors. k6 per-tag thresholds only receive data when the tag string exactly matches the threshold key. The assignment's threshold block uses the
… APIsuffix (e.g.name:Admin Login API), so the request tags use the identical names. This guarantees the thresholds actually evaluate real samples instead of silently passing on zero data. -
HTML report generation.
handleSummary()returns the report toReports/…-report.htmlviak6-reporter, plus a colourised console summary viak6-summary— no external tooling or post-processing needed. -
Book count surfaced twice. Task 2 logs the total book count to the console and records it as a custom
books_returnedgauge, so the number is visible in the HTML report as well as stdout.
| Symptom | Cause | Fix |
|---|---|---|
could not open 'Reports/…': no such file or directory |
Reports/ folder doesn't exist yet |
mkdir -p Reports before running |
| HTML report import fails / hangs | No internet access | The reporter is fetched from a CDN — connect to the internet |
| Task 1 thresholds show no data | Tag names edited out of sync with threshold keys | Keep request tags identical to the threshold selectors |
k6: command not found |
k6 not installed / not on PATH | See Prerequisites & Setup |
Batch 18 · Performance Testing Assignment Built with k6 ⚡ · Reports by k6-reporter

