-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjmeter-calendar-load-test.html
More file actions
120 lines (112 loc) · 10.8 KB
/
Copy pathjmeter-calendar-load-test.html
File metadata and controls
120 lines (112 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Apache JMeter calendar API lifecycle load-test case study with open-model arrivals, assertions, and cleanup-first safeguards.">
<title>JMeter Calendar Lifecycle Load Test | Denys Ishchuk</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<header class="nav-wrap">
<nav class="nav container" aria-label="Case study navigation">
<a class="brand" href="index.html" aria-label="Back to portfolio"><span>QA</span><b>DENYS ISHCHUK</b></a>
<div class="nav-links">
<a href="#overview">Overview</a><a href="#design">Design</a><a href="#run">Run</a>
<a class="button button-small" href="index.html#projects">All projects</a>
</div>
</nav>
</header>
<main id="main">
<section class="case-hero container" id="top">
<div class="eyebrow"><span class="status-dot"></span> Portfolio-safe performance engineering case study</div>
<h1>Calendar API <em>lifecycle load test.</em></h1>
<p class="case-lead">A parameterized Apache JMeter 5.6.3 plan that authenticates virtual users, creates workspace and personal calendars, verifies persisted records, and finishes every addressable lifecycle with an asserted DELETE.</p>
<div class="hero-actions">
<a class="button" href="projects/jmeter-calendar-lifecycle/calendar-lifecycle-load-test.jmx" download>Download the JMX <span aria-hidden="true">↓</span></a>
<a class="text-link" href="https://github.com/DenIce44/DenIce.github.io/tree/main/projects/jmeter-calendar-lifecycle">View source and documentation ↗</a>
</div>
<div class="metrics case-metrics" aria-label="Project facts">
<div><strong>5.6.3</strong><span>Apache JMeter</span></div>
<div><strong>7 calls</strong><span>per successful BOTH flow</span></div>
<div><strong>2 branches</strong><span>workspace and personal</span></div>
<div><strong>0 cache</strong><span>no Cache Manager dependency</span></div>
</div>
</section>
<section class="section container" id="overview">
<div class="section-heading"><div><span class="kicker">01 / OVERVIEW</span><h2>Business behavior under load.</h2></div><p>The workload measures complete calendar business flows rather than isolated requests. Arrival rate, target routes, input files, timeouts, and branch selection are runtime properties.</p></div>
<div class="skill-grid">
<article class="card"><span class="card-number">01</span><h3>Open workload model</h3><p>An Open Model Thread Group schedules new business-flow arrivals. Concurrency emerges from arrival rate and system response time.</p><div class="tags"><span>Arrival rate</span><span>Dynamic concurrency</span></div></article>
<article class="card"><span class="card-number">02</span><h3>Lifecycle assertions</h3><p>Create must return <code>201</code> and an ID. The list endpoint must return <code>200</code> and contain that exact ID before cleanup.</p><div class="tags"><span>HTTP assertions</span><span>JSONPath</span><span>Groovy</span></div></article>
<article class="card"><span class="card-number">03</span><h3>Cleanup-first structure</h3><p>DELETE remains a final sibling of verification, so a failed visibility assertion cannot skip cleanup when a valid ID exists.</p><div class="tags"><span>ID guard</span><span>Continue on error</span></div></article>
<article class="card"><span class="card-number">04</span><h3>Portable by design</h3><p>Targets and data paths are properties, public defaults are non-routable placeholders, and committed CSV rows are synthetic.</p><div class="tags"><span>Safe defaults</span><span>No secrets</span></div></article>
</div>
</section>
<section class="section projects-bg" id="design"><div class="container">
<div class="section-heading"><div><span class="kicker">02 / SCENARIO</span><h2>One arrival, complete ownership.</h2></div><p><code>BOTH</code> runs the two calendar lifecycles sequentially. <code>WORKSPACE</code>, <code>PERSONAL</code>, and weighted <code>MIXED</code> modes reuse the same test-plan structure.</p></div>
<div class="projects">
<article class="project"><div class="project-top"><span>STEP 01 / AUTH</span><b>→</b></div><h3>Authenticate</h3><p>Read a dedicated CSV account, sign in, extract the bearer token, and reject lifecycle traffic if token validation fails.</p><ul><li>Token state reset per arrival</li><li>Configurable token JSONPath</li><li>Cookie isolation between identities</li></ul><div class="tags"><span>POST</span><span>Bearer token</span></div></article>
<article class="project"><div class="project-top"><span>STEP 02 / WORKSPACE</span><b>→</b></div><h3>Create, verify, delete</h3><p>Create a unique workspace calendar, find its returned ID in the collection response, and perform asserted cleanup.</p><ul><li>POST expects 201</li><li>GET asserts exact ID visibility</li><li>DELETE expects 200</li></ul><div class="tags"><span>Workspace API</span><span>Lifecycle</span></div></article>
<article class="project"><div class="project-top"><span>STEP 03 / PERSONAL</span><b>✓</b></div><h3>Create, verify, delete</h3><p>Repeat the lifecycle against the personal calendar endpoints using independent input fields and cleanup state.</p><ul><li>Independent extracted ID</li><li>Finite unique input rows</li><li>Final mandatory cleanup step</li></ul><div class="tags"><span>Personal API</span><span>Cleanup</span></div></article>
</div>
</div></section>
<section class="section container">
<div class="section-heading"><div><span class="kicker">03 / RELIABILITY</span><h2>Failures stay explainable.</h2></div><p>The plan is designed to make the root HTTP failure visible while keeping deletion reachable wherever the API returned an addressable resource.</p></div>
<ol class="process">
<li><span>01</span><div><h3>Bound stalled calls</h3><p>Shared connection and response timeouts limit runaway thread accumulation in an open workload.</p></div></li>
<li><span>02</span><div><h3>Protect identity state</h3><p>Bearer variables and cookies are reset so authentication failures cannot leak a previous session into the next flow.</p></div></li>
<li><span>03</span><div><h3>Preserve cleanup after verify failure</h3><p><code>continue on error</code> and sibling cleanup controllers prevent an assertion failure from short-circuiting DELETE.</p></div></li>
<li><span>04</span><div><h3>Reserve cleanup time</h3><p>A final zero-arrival pause starts no new work while allowing active flows to reach their final deletion request.</p></div></li>
</ol>
<div class="case-note"><strong>Operational limit:</strong> a forced JVM stop, machine failure, or <code>Stop Test Now</code> can still interrupt in-flight DELETE calls. Graceful completion is part of the test contract.</div>
</section>
<section class="section case-config" id="run"><div class="container">
<div class="section-heading"><div><span class="kicker">04 / CONFIGURATION</span><h2>Safe defaults, explicit load.</h2></div><p>The repository cannot contact a real environment by default. An authorized target and private test data must be supplied at runtime.</p></div>
<div class="property-table-wrap">
<table class="property-table">
<thead><tr><th>Property</th><th>Safe default</th><th>Purpose</th></tr></thead>
<tbody>
<tr><td><code>apiHost</code></td><td><code>api.example.invalid</code></td><td>Target API host</td></tr>
<tr><td><code>loadSchedule</code></td><td><code>rate(1/sec) even_arrivals(10 sec)</code></td><td>Complete business-flow arrivals</td></tr>
<tr><td><code>calendarMode</code></td><td><code>BOTH</code></td><td>Workspace, personal, both, or mixed</td></tr>
<tr><td><code>cleanupGraceSeconds</code></td><td><code>20</code></td><td>Zero-arrival cleanup window</td></tr>
<tr><td><code>connectTimeoutMs</code></td><td><code>10000</code></td><td>Connection timeout</td></tr>
<tr><td><code>responseTimeoutMs</code></td><td><code>30000</code></td><td>Response timeout</td></tr>
</tbody>
</table>
</div>
<aside class="terminal case-terminal" aria-label="JMeter command example">
<div class="terminal-bar"><i></i><i></i><i></i><span>smoke-test.sh</span></div>
<pre><code>jmeter -n \
-t calendar-lifecycle-load-test.jmx \
-JapiHost=api.test.example \
-JusersCsv=data/users.local.csv \
-JcalendarsCsv=data/calendars.local.csv \
<span class="green">'-JloadSchedule=rate(1/sec) even_arrivals(10 sec)'</span> \
-JcleanupGraceSeconds=20 \
-l results/smoke.jtl</code></pre>
</aside>
<p class="case-caption">The rate is business-flow arrivals, not raw HTTP requests. A successful <code>BOTH</code> flow performs seven HTTP calls. Full property and data documentation is included with the source.</p>
</div></section>
<section class="section container">
<div class="section-heading"><div><span class="kicker">05 / VALIDATION</span><h2>Cleanup behavior, proven locally.</h2></div><p>The public plan is valid XML and loads with JMeter 5.6.3. No live capacity or production latency claims are included.</p></div>
<div class="validation-grid">
<div><strong>Forced workspace verify</strong><span>HTTP 500</span></div>
<div><strong>Workspace DELETE after failure</strong><span>HTTP 200</span></div>
<div><strong>Personal create / verify / delete</strong><span>201 / 200 / 200</span></div>
</div>
<div class="hero-actions case-actions">
<a class="button" href="projects/jmeter-calendar-lifecycle/calendar-lifecycle-load-test.jmx" download>Download test plan ↓</a>
<a class="text-link" href="projects/jmeter-calendar-lifecycle/README.md">Read implementation notes →</a>
</div>
</section>
<section class="contact"><div class="container contact-inner"><div><span class="kicker">PERFORMANCE WITH ACCOUNTABILITY</span><h2>Design load tests around business risk.</h2></div><div><a class="button button-light" href="index.html#projects">Back to selected work →</a><p>Sanitized project artifact · no private endpoints or credentials</p></div></div></section>
</main>
<footer class="container"><span>© <span id="year"></span> Denys Ishchuk</span><div><a href="https://github.com/DenIce44">GitHub</a><a href="https://www.linkedin.com/in/denys-i-273b3a247">LinkedIn</a></div></footer>
<script src="script.js"></script>
</body>
</html>