Repository navigation
test(ai): record and replay GLM integration tests - #16903
andrewheard wants to merge 1 commit into
Conversation
GeminiLanguageModel integration tests call live Gemini backends, which makes them slow, costly, and dependent on credentials. Add record and replay support using google/test-server so that pull requests, including those from forks, can run them in under a second without credentials. - Add INTEGRATION_TEST_MODE (live, record, or replay). In record and replay modes, IntegrationTestingBackend routes requests through a local test-server proxy and names each recording after the test and backend using a Test-Name header. Replay needs no credentials. - Add scripts/test-server.sh to download a pinned, checksum-verified test-server, redact credentials while recording, run tests serially, and re-record failed tests with a freshly started server. - When replay fails, explain each unmatched request by diffing it against its recording. - Audit recorded headers against an allowlist so that credential headers such as Authorization can't be committed, and strip noisy response headers such as Date. - Record all GLM integration suites against Firebase AI Logic. Disable the direct Developer API backend by default, and parameterize GeminiAPIClientIntegrationTests over the Firebase backends. - Add CI jobs that audit the recordings and replay all integration suites. Skip streamGenerateContentWithoutAuthThrows in replay mode for now: test-server v0.2.9 replays JSON error bodies on streaming URLs as server-sent events, so the client reports an HTTP error instead of an API error.
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
GeminiLanguageModel's integration tests run against live Gemini backends, so they're slow, cost money, need credentials, and fail when a backend misbehaves. This PR adds record and replay support using google/test-server. Every GLM integration suite can now replay from committed recordings in under a second, without credentials or network access to Gemini. That means they can run on every pull request, including PRs from forks.
How it works
INTEGRATION_TEST_MODEselects howIntegrationTestingBackendsends requests:live(default)recordreplaymakeModel()(and the newmakeClient()forGeminiAPIClient) sends aTest-Nameheader derived from the calling test's file, function, and backend, so each parameterized case gets its own recording underGeminiLanguageModel/Tests/TestServer/recordings/.test-server.yml. This makes replay a strict check on request encoding: an SDK change that alters a request fails replay until the affected tests are re-recorded.See
Tests/TestServer/README.mdfor details.Changes
Test harness (
GeminiTestUtilities)IntegrationTestModeandTestServerConfiguration. An unrecognizedINTEGRATION_TEST_MODEvalue stops the test run instead of silently falling back to live requests.recordandreplaymodes, routeIntegrationTestingBackendrequests to the local test-server proxy. Inreplaymode, every backend is available without credentials, the project ID isREDACTED, and the App Check exchange is skipped.authenticatedoption tomakeHeaderProviderso unauthenticated-request tests can be recorded..developerAPIinIntegrationTestingBackend.allCases, so integration tests target Firebase AI Logic only. It can be uncommented for manual testing.Tests
GeminiAPIClientIntegrationTestsoverIntegrationTestingBackend. The separate Firebase-specific test is now covered by the parameterized simple prompt test.Tooling (
GeminiLanguageModel/scripts)test-server.sh:test_server_diagnostics.py(Python standard library only):recording-policy.json, whatever its value. A new credential header such asAuthorization: Bearer …can't be committed by accident, even though gitleaks and trufflehog both missed it in testing. Noisy response headers such asDateare stripped. Only header names are printed, never values.CI (
sdk.geminilanguagemodel.yml)audit-recordings(Linux): runs the tooling unit tests and audits the committed recordings.replay-integration-tests(macOS): replays all integration suites without secrets, including on fork PRs. It fails if suites are skipped because FoundationModels is unavailable, rather than passing without running anything.Testing
REDACTED.thoughtSignature. Recording the same bug live never reproduced the backend's nondeterministic 400 in 9 runs.swift test --skip IntegrationTests,swift-format lint --strict, shellcheck, pyink, and the Python unit tests all pass.Known limitations and follow-ups
streamGenerateContentWithoutAuthThrowsis skipped in replay mode. test-server v0.2.9 replays a JSON error body on a streaming (alt=sse) URL as a server-sent event, soGeminiAPIClientreports.httpErrorinstead of.apiError. A ~15-line upstream fix that records each response's body format has been verified locally. Once it's released, the skip can be removed and the test-server version bumped.-test-iterationsand-retry-tests-on-failuredon't apply in replay mode. Replay is deterministic, so they aren't needed.API changes
None. All changes are in tests, test utilities, scripts, and CI.
#no-changelog