Ivan Petrović open to interesting problems Podgorica, Montenegro

I break software before your users do.

Ivan Petrović — Performance Engineer · Senior QA Automation Engineer · QA Lead. 7+ years turning quality into code: frameworks built from scratch at two SaaS companies, performance pipelines that fail builds — not people — and 11+ engineers mentored along the way.

$ now leading QA & performance at Fuel Me — an AI-powered procurement platform with Fortune 500 clients; JMeter as the daily driver, Playwright suite built from zero

$ next pioneering AI/LLM testing workflows — intelligent test generation and suites that heal themselves when the product changes

$ creed performance is a feature, quality gates should fail builds — not people, and a flaky test is a bug with your name on it

// selected work — open source, fully documented, green in CI

01 / performance engineering

Locust Performance Lab

Performance testing as code. A self-contained load testing framework that ships its own misbehaving system under test — one command spins up distributed load generation, live Grafana monitoring, automated memory-leak hunting, and an SLA gate that fails the CI build when latency budgets are breached.

View repo →
PythonLocust 2.xDockerFastAPIPrometheusGrafanaGitHub Actions

SLA gate — perf tests that can fail the build

Latency budgets live in slas.yml, per endpoint. A script parses Locust's CSV, prints a verdict table into the GitHub job summary, and exits non-zero on any breach. “A dashboard needs a human — an exit code scales.”

ScopeMetricActualLimit
POST /checkoutp95320 ms≤ 1500 msPASS
GET /search?q=[term]p95780 ms≤ 1000 msPASS
Aggregatederror rate0.00 %≤ 2.0 %PASS

🧠 Memory-leak hunter

Samples container memory under constant load, discards warm-up, fits a least-squares trend — and fails only when both growth rate and total growth blow their budgets. Demonstrated against a simulated ~50 KB/request leak:

leak on+95.5 MB · +2351 MB/h → exit 1
leak off+2.5 MB · stable → exit 0

Load shapes as ~15 lines of code

Stress, spike and soak profiles are LoadTestShape classes selected by one env var — one reviewed workload model serves every scenario.

class SpikeShape(LoadTestShape):
    """20-user baseline, sudden 10× spike."""
    def tick(self):
        t = self.get_run_time()
        if t < 120: return (20, 5)
        if t < 180: return (200, 50)  # the spike
        if t < 360: return (20, 50)   # recovery
        return None

📉 Regression detection, run over run

One run tells you where you are; comparing runs tells you where you're heading. Nightly CI diffs endpoint-by-endpoint and fails on p95 growth, throughput drops, or worsening error rate:

Endpointp95 base → nowΔ p95
GET /products/[id]67 → 72 ms+7.5 %OK
POST /checkout340 → 320 ms−5.9 %OK
Aggregated310 → 160 ms−48.4 %OK

🐳 Distributed by default

make up WORKERS=8 — Locust master/worker split in plain Docker Compose, FastHttpUser for ~10× RPS per generator. Same images scale across hosts or Kubernetes.

📊 Live observability

Pre-provisioned Grafana dashboard: RPS, p50/p95 overlaid with the user ramp, failures/s, and the leak-hunting memory panel — problems visible the moment they start, not in a PDF afterwards.

👥 Realistic workload model

75% browsers, 25% buyers running the full funnel as a SequentialTaskSet; catch_response marks a 200-without-order_id as a failure — wrong answers delivered quickly are still wrong.

smoke · baseline · stress · spike · soak · leak-test · compare — every scenario is one make target, every gate is an exit code

02 / test automation

Booking.com Automation Framework

E2E that survives a live production site. Playwright + TypeScript framework running green against the real booking.com — anti-bot protection, A/B DOM swaps, white-label variants and all — covering Stays, Flights, Car rentals and Attractions, plus accessibility and API-level checks.

View repo →
Playwright 1.60TypeScript strictPOMaxe-coreESLint 9Sharded CI

🩹 Self-healing locator engine

Every element is an ElementDefinition with ordered fallback candidates. When the primary selector dies mid-day (booking.com A/B tests constantly), candidates are polled round-robin, the winner is logged as a healing event, and non-volatile heals are persisted to a git-committed store so future runs try them first.

destinationInput: {
  key: 'stays.searchbox.destinationInput',
  candidates: [
    'input[name="ss"]',                            // primary
    '[data-testid="destination-container"] input', // fallback 1
    'input[placeholder*="Where are you going"]',   // fallback 2
  ],
}

📡 A real heal, captured in CI

Worker processes append events to their own files; a custom reporter consolidates them after the run. The engine is itself covered by E2E tests.

{
  "key": "flights.results.flightCards",
  "failed": ["[data-testid=…_card]"],
  "healed": "[aria-label^='Result item']",
  "persistPreferred": true
}

🩹 healed → logged → persisted → suite stays green

🌍 Live-site quirks, engineered around

  • Flights served as Kayak white-label in some regions — variant auto-detected, stable deep-link scheme used
  • Sign-in popup at random moments — addLocatorHandler auto-dismisses whenever it blocks
  • /flights/ redirect trap — navigation enters via the header tab, like a real user
  • A/B DOM swaps — absorbed by the healer, variants kept as candidates

🧱 Layered architecture

tests/*.spec.tsintent only — arrange data, call page methods, assert
fixturespage objects + auto fixtures (tracker blocking, console-error capture)
page objectslocators + user actions · never assert
healing enginecandidate resolution + persistence

Plus a data layer with fluent builders — dates always generated relative to “now”, so the suite never rots from hardcoded test data.

Beyond the happy path

axe-core WCAG 2.0 A/AA scan gating on critical violations, toMatchAriaSnapshot structural assertions, and APIRequestContext canaries at the HTTP level.

⚙️ CI built to scale

Static checks fail fast → sharded test matrix → blob reports merged into one HTML report. PR annotations, nightly cron, manual dispatch with tag filter. Scaling = extending the shard matrix.

🏷 14 tests, 9 suites, 3 browsers

Tag-driven: @smoke @stays @flights @cars @attractions @a11y @api @healer compose with --grep regexes. Verified green against the live site, Chromium / Firefox / WebKit.

page objects never assert · specs never touch selectors · selectors heal themselves

// where this was forged

Experience

Jun 2024 — now

Performance Engineer · Senior QA Automation · Team Lead @ Fuel Me

AI-powered fuel procurement platform, Fortune 500 clients, Series A.

  • Own platform performance end to end: load, stress, spike, endurance & scalability with JMeter against APIs and full user journeys — bottlenecks and memory leaks hunted at production scale, SLAs and baselines set, perf checks wired into CI/CD
  • Built the entire automation framework from scratch (Playwright + Node.js) — 100% of regression automated
  • Pioneered AI/LLM workflows for test-case generation, script creation and auto-healing
  • Leading a QA team of 3 — strategy, mentoring, code reviews
Apr 2020 — Jun 2024

QA Engineer @ SynergySuite

Restaurant management platform for global enterprise chains.

  • Joined a 100% manual team → built the automation framework from scratch (Selenium, Java, TestNG)
  • Mentored 8 QA engineers through the move to automation; by departure, 100% of regression was automated
  • Web + mobile (iOS/Android), API testing, SQL validation, CI/CD with Jenkins & GitHub Actions
Sep 2019 — Apr 2020

Technical Support Specialist @ SynergySuite

L1/L2 for enterprise clients across time zones — logs, SQL, bug reproduction.

Jan 2014 — Sep 2019

Implementation Technician · Team Lead @ VG GROUP

Led implementations of CRM/ERP/POS across 50+ hospitality & retail clients; data migrations, Tier 2/3 support.

Dec 2016 — Sep 2018

WordPress Developer @ Inch Agency

Custom themes & plugins from scratch (PHP, MySQL, JS); SEO and page-speed tuning.

$ cat education.txt BSc Applied Computer Science · University of Montenegro · 2010–2013

// tools are interchangeable, judgment isn't

Stack

⚡ performance/

JMeter (daily driver) · Locust · k6 · Gatling — load, stress, spike, soak; bottleneck analysis, memory-leak detection, SLAs & baselines, CI perf gates

🤖 automation/

Playwright · Selenium · TestNG — framework architecture, self-healing strategies, API testing, mobile (iOS/Android), cross-browser

📈 observability/

Grafana · Prometheus · OpenTelemetry · Sentry — dashboards as code, root-cause analysis of latency spikes and throughput degradation

💻 languages/

TypeScript · JavaScript · Node.js · Java · Python · SQL · PHP

🧠 ai-devops/

Custom AI/LLM test workflows · intelligent test generation · GitHub Actions · Jenkins · Docker · Linux

👥 leadership/

Team lead ×2 · 11+ engineers mentored · code review culture · Agile/Scrum · JIRA · Confluence

// ping me

Let's make something
fast and unbreakable.