vero.plan/v1

API tests that know which requests must not overlap

vero is one static Go binary. It reads a YAML plan, builds a graph of its tasks and runs HTTP, gRPC, WebSocket, SQL, shell and script steps with assertions. A task that spends a shared budget, like a rate limit, holds a named resource, and two holders never run at once.

Why holds exists

Send four requests against a limit of three and the fourth should get a 429. Sent one after another, it does. Split into four independent tasks that run in parallel, the 429 lands on whichever request arrives last. Against nginx's limit_req at --jobs 8, that version passed 135 runs out of 300.

A vero plan has two kinds of edge. needs is a data dependency, derived from the template references in a task. holds is a claim on a named resource. It orders nothing, but no two tasks that hold one exclusive resource overlap.

resources:
  - name: ratelimit/orders-api-key
    mode: exclusive

tasks:
  - name: rate-limit-trips-on-fourth
    holds: [ratelimit/orders-api-key]
    steps:
      - http:
          method: GET
          url: "{{ env.baseUrl }}/orders"
          headers: { Authorization: "Bearer {{ tasks.login.results.token }}" }
        repeat: { count: 4, mode: serial }
        assert:
          - responses count 4
          - responses[0:3] all (it.status == 200)
          - responses[3].status == 429
          - responses[3].headers["Retry-After"] != nil
From examples/rate-limit.yaml. It passes 50 runs out of 50 at --jobs 1 and at --jobs 8. The same shape passed 300 out of 300against nginx.

Run it

Build from source, run the sample API in a foreground terminal, inspect and run a plan in another, then configure a health check for your own service. TheGetting started guideincludes the commands, prerequisites, expected results, and fixture shutdown.

Exit codes

A CI job can tell a failed assertion from a server that never answered without reading the output.

CodeMeaning
0Everything passed, or was skipped on purpose.
1An assertion failed.
2A step errored or timed out.
3The run did not complete.
4Only teardown failed.
64The plan is invalid, and nothing was sent.

What else is in it

Steps
http, graphql, ws, grpc, sql on SQLite and Postgres, exec, waitFor, fixture, and script for anything a plan cannot say.
Reports
A summary line with seven terminal states, an NDJSON event log, JUnit, TAP and an HTML report.
Diagnosis
A flake report from --repeat, a hint when a task fails only above --jobs 1, --explain, and lints.
Secrets
Values from secretRef, and results marked secret, are scrubbed from every output vero writes.
Import
vero import turns Postman collections, Hurl files and curl commands into plans.
One file
A plan has no includes and no loops. vero knows every task and every request before it opens a socket.
verodocs