An extensible test framework for CLI programs, REST APIs, GraphQL, gRPC, browsers, and network protocols. Declarative YAML tests. Zero third-party dependencies.
suite: "E-Commerce API"
tags: [api, loadtest]
execution:
mode: weighted
concurrency: 100
duration: "10m"
repeat: 0
fleet:
providers:
- provider: static
weight: 100
ttl: 0
static:
ssh:
user: scrutineer
key_file: ~/.ssh/ed25519
nodes: [10.0.1.10, 10.0.1.11]
interactions:
- name: "User session"
weight: 7
mode: sequential
tests:
- name: "Login"
connector: http
steps:
- action: request
method: POST
path: /api/auth/login
body:
email: "${fn:concat(random_string(alpha, 5, 8), '@test.com')}"
password: "${fn:env_or('TEST_PASSWORD', 'secret')}"
assert:
- field: status
operator: equal
expected: 200
capture:
token: body.token
- name: "Browse catalog"
connector: http
steps:
- action: request
method: GET
path: /api/products
headers:
Authorization: "Bearer ${capture.token}"
query:
page: "${fn:random_int(1, 50)}"
assert:
- field: status
operator: equal
expected: 200
- field: elapsed_ms
operator: less_than
expected: 3000
- name: "Checkout"
weight: 2
mode: sequential
tests:
- name: "Place order"
connector: http
steps:
- action: request
method: POST
path: /api/orders
body:
product_id: "${fn:random_int(1, 1000)}"
idempotency_key: "${fn:uuid()}"
assert:
- field: status
operator: status_class
expected: "2xx"
- name: "Admin"
weight: 1
mode: random
tests:
- name: "Pull report"
connector: http
steps:
- action: request
method: GET
path: /api/admin/reports
assert:
- field: status
operator: equal
expected: 200Everything you need for comprehensive testing, in a single binary with zero dependencies.
Define tests as data, not code. Describe what to assert, not how to execute. Familiar to Playwright and assertion-based test users.
CLI, HTTP, SSH, gRPC, GraphQL, and browser connectors. Add new protocols by implementing a single Go interface.
Headless Chromium, Firefox, and WebKit via Chrome DevTools Protocol. Selectors, interactions, screenshots, network interception.
Parallel test execution distributed across nodes via SSH. Configurable concurrency, ramp-up, and duration. Locust-style scaling.
Every test captures timing data automatically. Structured binary TLV logs with nanosecond timestamps for benchmark analysis.
Built with the Go standard library. No node_modules, no pip packages, no dependency hell. One binary, every platform.
Built-in test coverage measurement with configurable thresholds. Know exactly which tests ran, which steps executed, which assertions fired.
Declarative fuzz targets integrated with Go's built-in fuzzing. Corpus management and automated edge-case discovery.
Equality, contains, regex, JSON path, HTTP status, headers, timing, collections. Extensible assertion library with clear error messages.
Test anything that speaks a protocol.
| Feature | Connector | Status | Features |
|---|---|---|---|
| HTTP/1.1, HTTP/2 | http | v0.0.1 | TLS 1.2/1.3, self-signed certs, request/response assertions |
| REST APIs | http | v0.0.1 | CRUD, auth (Bearer, Basic, API key), JSON/XML, pagination, HATEOAS |
| GraphQL | http | v0.0.1 | Queries, mutations, subscriptions, introspection, variables |
| gRPC / Protobuf | grpc | v0.0.1 | Unary, client/server/bidi streaming, .proto + reflection |
| SSH | ssh | v0.0.1 | Key-based auth, command execution, tunneling |
| CLI Programs | cli | v0.0.1 | stdin/stdout/stderr, exit codes, filesystem side-effects |
| Chromium / Firefox / WebKit | browser | v0.0.1 | CDP, selectors, interactions, screenshots, network mocking |
| HTTP/3 (QUIC) | http | planned | Pending Go stdlib or from-scratch QUIC |
| SMTP | smtp | planned | Send, auth, envelope validation |
| IMAP | imap | planned | Mailbox access, search, fetch |
One command. No dependencies.
$ go install github.com/asymmetric-effort/scrutineer/cmd/scrutineer@latestOr download a pre-built binary from Releases for Linux, macOS, or Windows (AMD64 / ARM64).
# Install scrutineer
$ go install github.com/asymmetric-effort/scrutineer/cmd/scrutineer@latest
# Install browsers (for browser testing)
$ scrutineer browsers install
# Run tests
$ scrutineer run
# Run with JSON output
$ scrutineer run --format json
# Dump binary telemetry logs
$ scrutineer log-dump scrutineer.logBuild once, test everywhere.
AMD64 / ARM64
AMD64 / ARM64
AMD64 / ARM64