# Redis (RESP) load test, driven by the `loadr-plugin-redis` native protocol
# plugin.
#
# Redis is NOT built into loadr core — it is a runtime-loadable plugin that
# speaks RESP directly over TCP (no `redis` crate, no OpenSSL). The plugin
# declares the `redis://` (and `rediss://`) URL scheme, so once it is installed
# a request to a `redis://` URL routes straight to it; no explicit `protocol:`
# is needed.
#
# Each request runs one command from its `plugin.command` array (argv form).
# loadr records the command latency in `redis_req_duration` and counts requests
# in `redis_reqs`. A successful reply is status 0; a RESP error reply is status
# 1 and fails the request.
#
# Build + install the plugin, then run:
#   cargo build -p loadr-plugin-redis --release
#   mkdir -p dist && cp plugins/loadr-plugin-redis/plugin.toml dist/ \
#     && cp target/release/libloadr_plugin_redis.so dist/
#   loadr plugin install dist
#   loadr run examples/30-redis.yaml
#
# Or point the plan's `plugins:` entry at the built artifact directly (below).
name: redis
description: SET/GET/INCR/PING against Redis via loadr-plugin-redis

plugins:
  # Resolve `redis` by name from the plugins dir (after `loadr plugin install`).
  # To run straight from a build tree instead, set:
  #   path: target/release/libloadr_plugin_redis.so
  - name: redis

scenarios:
  # Steady write/read churn: each VU owns its own session key.
  cache_churn:
    executor: constant-vus
    vus: 20
    duration: 15s
    flow:
      - request:
          name: set session
          url: redis://cache.example.com:6379
          plugin:
            command: ["SET", "session:${vu}", "active"]
          checks:
            - { type: status, equals: 0 }            # +OK, not a RESP error
            - { type: body_contains, value: OK }
      - request:
          name: get session
          url: redis://cache.example.com:6379
          plugin:
            command: ["GET", "session:${vu}"]
          checks:
            - { type: body_contains, value: active }
            - { type: duration, name: cache is fast, max: 50ms }
      - request:
          name: expire session
          url: redis://cache.example.com:6379/0
          plugin:
            command: ["EXPIRE", "session:${vu}", "60"]
          assert:
            - { type: status, equals: 0 }

  # Hot counter: hammer a single INCR key at a fixed rate.
  hot_counter:
    executor: constant-arrival-rate
    rate: 200
    duration: 15s
    pre_allocated_vus: 30
    max_vus: 100
    flow:
      - request:
          name: ping
          url: redis://cache.example.com:6379
          plugin:
            command: ["PING"]
          checks:
            - { type: body_contains, value: PONG }
      - request:
          name: increment counter
          url: redis://cache.example.com:6379
          plugin:
            command: ["INCR", "page:views"]
          assert:
            - { type: status, equals: 0 }
          checks:
            - { type: body_matches, pattern: '^[0-9]+$' }  # integer reply

thresholds:
  checks: [ "rate>0.99" ]
  redis_req_duration: [ "p(95)<100ms" ]
