Skip to content

Commit 6bf95dc

Browse files
committed
test(recorded): improve cassette refresh workflow
1 parent 4aa1590 commit 6bf95dc

2 files changed

Lines changed: 64 additions & 20 deletions

File tree

Makefile

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.PHONY: help
2-
.PHONY: test test-parallel test-serial test-benchmark test-watch test-coverage test-profile record-tests check-record-test-env warm-fastembed-cache
2+
.PHONY: test test-parallel test-serial test-benchmark test-watch test-coverage test-profile record-cassettes rewrite-cassettes replay-cassettes snapshot-cassettes check-record-test-env warm-fastembed-cache
33
.PHONY: docs-fern docs-fern-strict docs-fern-live docs-fern-preview-watch docs-fern-generate-sdk docs-fern-fix-empty-links docs-check-redirects docs-fern-publish-staging docs-fern-publish-public
44
.PHONY: pre-commit
55

@@ -14,6 +14,8 @@ DIST ?= worksteal
1414

1515
PYTEST ?= poetry run pytest
1616
RECORDED_TESTS ?= tests/recorded
17+
RECORDED_RECORD_MODE ?= once
18+
RECORDED_SNAPSHOT_MODE ?= create
1719
RECORDED_REQUIRED_KEYS ?= OPENAI_API_KEY NVIDIA_API_KEY
1820
RECORDED_REPLAY_ENV ?= env -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY -u http_proxy -u https_proxy -u all_proxy
1921
# These targets assume a Unix-like shell for env -u; use bash, Git Bash, or WSL on Windows.
@@ -46,11 +48,20 @@ test-coverage:
4648
test-profile:
4749
$(PYTEST) -vv --profile-svg $(ARGS) $(TEST)
4850

49-
record-tests: check-record-test-env
50-
$(PYTEST) $(RECORDED_TESTS) --record-mode=all -m "not fake_cassette"
51-
$(RECORDED_REPLAY_ENV) $(PYTEST) $(RECORDED_TESTS) --block-network --inline-snapshot=create
51+
record-cassettes: check-record-test-env
52+
$(PYTEST) $(RECORDED_TESTS) --record-mode=$(RECORDED_RECORD_MODE) -m "not fake_cassette"
53+
$(RECORDED_REPLAY_ENV) $(PYTEST) $(RECORDED_TESTS) --block-network --inline-snapshot=$(RECORDED_SNAPSHOT_MODE)
5254
$(RECORDED_REPLAY_ENV) $(PYTEST) $(RECORDED_TESTS) --block-network
5355

56+
rewrite-cassettes:
57+
$(MAKE) record-cassettes RECORDED_RECORD_MODE=rewrite RECORDED_SNAPSHOT_MODE=fix
58+
59+
replay-cassettes:
60+
$(RECORDED_REPLAY_ENV) $(PYTEST) $(RECORDED_TESTS) --block-network
61+
62+
snapshot-cassettes:
63+
$(RECORDED_REPLAY_ENV) $(PYTEST) $(RECORDED_TESTS) --block-network --inline-snapshot=fix
64+
5465
check-record-test-env:
5566
@missing=""; \
5667
for key in $(RECORDED_REQUIRED_KEYS); do \
@@ -60,7 +71,7 @@ check-record-test-env:
6071
done; \
6172
if [ -n "$$missing" ]; then \
6273
printf '%s\n' "Missing required env var(s):$$missing" \
63-
"Set them before make record-tests, or override RECORDED_REQUIRED_KEYS for a focused refresh."; \
74+
"Set them before make record-cassettes, or override RECORDED_REQUIRED_KEYS for a focused refresh."; \
6475
exit 2; \
6576
fi
6677

@@ -107,7 +118,10 @@ help:
107118
' make test-benchmark [ARGS="-q"]' \
108119
' make test-parallel [TEST=path] [WORKERS=auto] [ARGS="-q --tb=short"]' \
109120
' make test-watch [TEST=path]' \
110-
' make record-tests [RECORDED_TESTS=tests/recorded] [RECORDED_REQUIRED_KEYS="OPENAI_API_KEY NVIDIA_API_KEY"]' \
121+
' make record-cassettes [RECORDED_TESTS=tests/recorded] [RECORDED_RECORD_MODE=once] [RECORDED_SNAPSHOT_MODE=create] [RECORDED_REQUIRED_KEYS="OPENAI_API_KEY NVIDIA_API_KEY"]' \
122+
' make rewrite-cassettes [RECORDED_TESTS=tests/recorded] [RECORDED_REQUIRED_KEYS="OPENAI_API_KEY NVIDIA_API_KEY"]' \
123+
' make replay-cassettes [RECORDED_TESTS=tests/recorded]' \
124+
' make snapshot-cassettes [RECORDED_TESTS=tests/recorded]' \
111125
'' \
112126
'Tests:' \
113127
' test Run pytest.ini testpaths with pytest-xdist' \
@@ -117,7 +131,10 @@ help:
117131
' test-watch Run pytest in watch mode' \
118132
' test-coverage Run pytest with coverage' \
119133
' test-profile Run pytest with profiling' \
120-
' record-tests Refresh cassettes with required provider keys, fill snapshots, and verify replay' \
134+
' record-cassettes Record missing or selected cassettes, fill snapshots, and verify replay' \
135+
' rewrite-cassettes Rewrite selected cassettes, fill snapshots, and verify replay' \
136+
' replay-cassettes Verify selected cassettes offline without recording' \
137+
' snapshot-cassettes Update inline snapshots from existing cassettes offline' \
121138
' warm-fastembed-cache Prime the repo-local FastEmbed cache' \
122139
'' \
123140
'Docs:' \

tests/recorded/README.md

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,34 +75,61 @@ Replay mode installs dummy API keys from `tests/recorded/utils.py`. A cassette m
7575

7676
## Refresh
7777

78-
Refresh only in a trusted environment with real provider credentials. The full
79-
record -> fill-snapshots -> verify loop is wrapped in a make target:
78+
Refresh only in a trusted environment with real provider credentials. The
79+
record -> fill-snapshots -> verify loop is wrapped in make targets.
8080

8181
```bash
82-
OPENAI_API_KEY=... NVIDIA_API_KEY=... make record-tests
82+
OPENAI_API_KEY=... NVIDIA_API_KEY=... make record-cassettes
8383
```
8484

85-
The full target requires `OPENAI_API_KEY` and `NVIDIA_API_KEY` before it starts
86-
recording. For a focused refresh that only touches one provider, override the
87-
preflight list:
85+
`record-cassettes` defaults to `RECORDED_RECORD_MODE=once` and
86+
`RECORDED_SNAPSHOT_MODE=create`, which records missing cassettes, fills empty
87+
snapshots, and replays existing cassettes. This is the safest mode when adding
88+
new tests because it will not rewrite unrelated existing cassettes selected by
89+
the same path.
90+
91+
For a focused new cassette that only touches one provider, pass the test node and
92+
override the preflight list:
8893

8994
```bash
90-
OPENAI_API_KEY=... make record-tests RECORDED_TESTS=path::test_name RECORDED_REQUIRED_KEYS=OPENAI_API_KEY
95+
OPENAI_API_KEY=... make record-cassettes \
96+
RECORDED_TESTS=tests/recorded/rails/public_api/test_generate.py::test_new_case \
97+
RECORDED_REQUIRED_KEYS=OPENAI_API_KEY
9198
```
9299

93-
Or run the recording step alone:
100+
`RECORDED_TESTS` is passed directly to pytest, so it can be a single test, a
101+
test class, several files, or a directory:
94102

95103
```bash
96-
poetry run pytest tests/recorded --record-mode=all -m "not fake_cassette" -v
104+
OPENAI_API_KEY=... make record-cassettes \
105+
RECORDED_TESTS="tests/recorded/rails/public_api/test_generate.py tests/recorded/clients/test_openai_chat.py" \
106+
RECORDED_REQUIRED_KEYS=OPENAI_API_KEY
97107
```
98108

99-
For a focused rewrite:
109+
For an intentional rewrite of existing cassettes, use `rewrite-cassettes`:
100110

101111
```bash
102-
poetry run pytest tests/recorded/rails/public_api/test_generate.py::test_openai_generate_async_public_contract --record-mode=rewrite -v
112+
OPENAI_API_KEY=... make rewrite-cassettes \
113+
RECORDED_TESTS=tests/recorded/rails/public_api/test_generate.py::test_openai_generate_async_public_contract \
114+
RECORDED_REQUIRED_KEYS=OPENAI_API_KEY
103115
```
104116

105-
The refresh workflow uploads cassettes as artifacts for review and does not commit them.
117+
`rewrite-cassettes` uses `RECORDED_RECORD_MODE=rewrite` and
118+
`RECORDED_SNAPSHOT_MODE=fix`, so changed recorded outputs update existing inline
119+
snapshots before the final offline replay verification.
120+
121+
For a full trusted refresh, set the record mode explicitly:
122+
123+
```bash
124+
OPENAI_API_KEY=... NVIDIA_API_KEY=... make record-cassettes RECORDED_RECORD_MODE=all RECORDED_SNAPSHOT_MODE=fix
125+
```
126+
127+
Replay and snapshot-only workflows do not need real provider credentials:
128+
129+
```bash
130+
make replay-cassettes RECORDED_TESTS=tests/recorded/rails/public_api/test_generate.py::test_openai_generate_async_public_contract
131+
make snapshot-cassettes RECORDED_TESTS=tests/recorded/rails/public_api/test_generate.py::test_openai_generate_async_public_contract
132+
```
106133

107134
## Cassettes
108135

@@ -135,7 +162,7 @@ poetry run pytest tests/recorded/rails --block-network --inline-snapshot=review
135162
```
136163

137164
Snapshot formatting uses `ruff format` through `[tool.inline-snapshot]` in `pyproject.toml`.
138-
Snapshot create/fix/review runs must be serial. Use `make record-tests` or a
165+
Snapshot create/fix/review runs must be serial. Use `make record-cassettes` or a
139166
direct `poetry run pytest ... --inline-snapshot=<mode>` command; the default
140167
`make test` path uses xdist, where inline-snapshot disables update and report
141168
modes.

0 commit comments

Comments
 (0)