# k6 Load Tests for Cart API

This directory contains a k6 script (`cart_load_test.js`) to stress and observe the cart actor HTTP API.

## Contents

- `cart_load_test.js` – primary k6 scenario script
- `README.md` – this file

## Prerequisites

- Node not required (k6 runs standalone)
- k6 installed (>= v0.43 recommended)
- Prometheus + Grafana (optional) if you want to correlate with the dashboard you generated
- A running cart service exposing HTTP endpoints at (default) `http://localhost:8080/cart`

## Endpoints Exercised

The script exercises (per iteration):

1. `GET /cart/` – ensure / fetch cart state (creates cart if missing; sets `cartid` & `cartowner` cookies)
2. `POST /cart/` – add item mutation (random SKU & quantity)
3. `GET /cart/` – fetch after mutations
4. `GET /cart/checkout` – occasionally (~2% of iterations) to simulate checkout start

You can extend it easily to hit deliveries, quantity changes, or removal endpoints.

## Environment Variables

| Variable        | Purpose                                      | Default                 |
|-----------------|----------------------------------------------|-------------------------|
| `BASE_URL`      | Base URL root (either host or host/cart)     | `http://localhost:8080/cart` |
| `VUS`           | VUs for steady_mutations scenario            | `20`                    |
| `DURATION`      | Duration for steady_mutations scenario       | `5m`                    |
| `RAMP_TARGET`   | Peak VUs for ramp_up scenario                 | `50`                    |

You can also disable one scenario by editing `options.scenarios` inside the script.

Example run:

```bash
k6 run \
  -e BASE_URL=https://cart.prod.example.com/cart \
  -e VUS=40 \
  -e DURATION=10m \
  -e RAMP_TARGET=120 \
  k6/cart_load_test.js
```

## Metrics (Custom)

The script defines additional k6 metrics:

- `cart_add_item_duration` (Trend) – latency of POST add item
- `cart_fetch_duration` (Trend) – latency of GET cart state
- `cart_checkout_duration` (Trend) – latency of checkout
- `cart_items_added` (Counter) – successful add item operations
- `cart_checkout_calls` (Counter) – successful checkout calls

Thresholds (in `options.thresholds`) enforce basic SLO:
- Mutation failure rate < 2%
- p90 mutation latency < 800 ms
- p99 overall HTTP latency < 1500 ms

Adjust thresholds to your environment if they trigger prematurely.

## Cookies & Stickiness

The script preserves:
- `cartid` – cart identity (server sets expiry separately)
- `cartowner` – owning host for sticky routing

If your load balancer or ingress enforces affinity based on these cookies, traffic will naturally concentrate on the originally claimed host for each cart under test.

## SKU Set

SKUs used (randomly selected each mutation):

```
778290 778345 778317 778277 778267 778376 778244 778384
778365 778377 778255 778286 778246 778270 778266 778285
778329 778425 778407 778418 778430 778469 778358 778351
778319 778307 778278 778251 778253 778261 778263 778273
778281 778294 778297 778302
```

To add/remove SKUs, edit the `SKUS` array. Keeping it non-empty and moderately sized helps randomization.

## Extending the Script

### Add Quantity Change

```js
function changeQuantity(itemId, newQty) {
  const payload = JSON.stringify({ Id: itemId, Qty: newQty });
  http.put(baseUrl() + '/', payload, { headers: headers() });
}
```

### Remove Item

```js
function removeItem(itemId) {
  http.del(baseUrl() + '/' + itemId, null, { headers: headers() });
}
```

### Add Delivery

```js
function addDelivery(itemIds) {
  const payload = JSON.stringify({ provider: "POSTNORD", items: itemIds });
  http.post(baseUrl() + '/delivery', payload, { headers: headers() });
}
```

You can integrate these into the iteration loop with probabilities.

## Output Summary

`handleSummary` outputs a JSON summary to stdout:
- Average & p95 mutation latencies (if present)
- Fetch p95
- Checkout count
- Check statuses

Redirect or parse that output for CI pipelines.

## Running in CI

Use shorter durations (e.g. `DURATION=2m VUS=10`) to keep builds fast. Fail build on threshold breaches:

```bash
k6 run -e BASE_URL=$TARGET -e VUS=10 -e DURATION=2m k6/cart_load_test.js || exit 1
```

## Correlating with Prometheus / Grafana

During load, observe:
- `cart_mutations_total` growth and latency histograms
- Event log write rate (`cart_event_log_appends_total`)
- Pool usage (`cart_grain_pool_usage`) and spawn rate (`cart_grain_spawned_total`)
- Failure counters (`cart_mutation_failures_total`) ensure they remain low

If mutation latency spikes without high error rate, inspect external dependencies (e.g., product fetcher or Klarna endpoints).

## Common Tuning Tips

| Symptom                             | Potential Adjustment                              |
|------------------------------------|---------------------------------------------------|
| High latency p99                   | Increase CPU/memory, optimize mutation handlers   |
| Pool at capacity                   | Raise pool size argument or TTL                   |
| Frequent cart eviction mid-test    | Confirm TTL is sliding (now 2h on mutation)       |
| High replay duration               | Consider snapshot + truncate event logs           |
| Uneven host load                   | Verify `cartowner` cookie is respected upstream   |

## Safety / Load Guardrails

- Start with low VUs (5–10) and short duration.
- Scale incrementally to find saturation points.
- If using production endpoints, coordinate off-peak runs.

## License / Attribution

This test script is tailored for your internal cart actor system; adapt freely. k6 is open-source (AGPL v3). Ensure compliance if redistributing.

---

Feel free to request:
- A variant script for spike tests
- WebSocket / long poll integration (if added later)
- Synthetic error injection harness

Happy load testing!