# REST API contract tests

Shell-based contract tests that exercise the Salesforce REST API
compatibility surface against a running backend. Each script is a
dimension probe — exit code is the number of failed dimensions.

These are **live integration tests**, not self-contained deterministic
probes. They require a running backend, live TiDB, valid OAuth
credentials, `jq` on PATH, and installed metadata packs.

## Prerequisites

- A running serviceified CRM deployment with Runtime and the L1 AppService
  activated through its delivery runbook. Point `BACKEND_HOST` / `BACKEND_PORT`
  at its public ingress; the scripts default to `127.0.0.1:3001`, so override
  both values when the deployment uses another address. See
  [the current bootstrap guide](../../../docs/open-source/self-hosting/backend-greenfield-bootstrap.md).
- TiDB reachable at `TIDB_HOST:TIDB_PORT` (default `127.0.0.1:4000`).
- `jq` available on PATH.
- A standard CRM pack installed so that standard objects (User, Account,
  …) are available in the metadata layer.
- Admin credentials for OAuth login (override via `ADMIN_EMAIL` /
  `ADMIN_PASS`). Default: `admin@example.invalid` / `Admin123!`.
- A connected app for password-grant login (override via `CLIENT_ID` /
  `CLIENT_SECRET`). Default: `test-gosf-client` / `test-gosf-secret-123`.

## Scripts

### `verify_query_pagination.sh` (3 contract dimensions)

| Dim | Contract |
|-----|----------|
| 1 | Response envelope: `totalSize` (number), `done` (bool), `records` (array) |
| 2 | `done=true` when limit ≥ total rows |
| 3 | Malformed SOQL → HTTP 400 with SF `errorCode` |

Optional non-contract diagnostic:

```bash
RUN_QUERYMORE_DIAGNOSTIC=true ./tests/contract/rest_api/verify_query_pagination.sh
```

That diagnostic exercises the current LIMIT/OFFSET cursor implementation only.
It must not be treated as Salesforce v63 queryMore coverage. Native
`Sforce-Query-Options: batchSize` pagination remains a deferred subcase.

### `verify_search_strict.sh` (5 dimensions)

| Dim | Contract |
|-----|----------|
| 1 | SOSL response envelope: `searchRecords` (array) |
| 2 | Scoped search (`IN NAME FIELDS`) returns valid envelope |
| 3 | RETURNING clause with field projection |
| 4 | Missing `q` parameter → HTTP 400 |
| 5 | Malformed SOSL → HTTP 400 with SF `errorCode` |

### `verify_audit_gating.sh` (5 dimensions)

| Dim | Contract |
|-----|----------|
| 1 | `<Object>History` query returns valid SOQL envelope |
| 2 | Unsupported predicate (`WHERE Field = 'X'`) → HTTP 400 `MALFORMED_QUERY` |
| 3 | History without `ParentId` filter → HTTP 200 (optional filter per backend §5.1) |
| 4 | Head-row suppression (`Field ≠ '__record__'`) |
| 5 | Empty valid envelope for an unrelated parent with no history |

## CI status

These scripts are **not yet wired into CI**. They must be run manually
against a live local backend. A future PR should add a GitHub Actions
workflow or Go test wrapper that bootstraps the backend, runs these
scripts, and reports results as a required check.

## Running

```bash
# All scripts — run from repo root
./tests/contract/rest_api/verify_query_pagination.sh
./tests/contract/rest_api/verify_search_strict.sh
./tests/contract/rest_api/verify_audit_gating.sh

# Custom backend port
BACKEND_PORT=3301 ./tests/contract/rest_api/verify_query_pagination.sh

# Custom TiDB (e.g. docker-compose)
TIDB_PORT=4001 ./tests/contract/rest_api/verify_search_strict.sh
```

## Output

- Diagnostics and per-dimension results go to **stderr**.
- Exit code `0` = all dimensions passed; non-zero = number of failures.
- Detailed logs are written to `$OUT_DIR` (default `/tmp/sfmeta/run/contract`).

## Relationship to L0 completeness tests

The `tests/integration/l0-completeness/` scripts exercise the L0 platform
substrate (pack install, idempotency, source disappearance, admin overrides).

These REST contract tests exercise the L1/Salesforce-compatibility API
surface. They are kept separate to avoid conflating platform substrate
behavior with API parity behavior.
