Establishes the integration testing foundation and parameterized test suites for `GeminiLanguageModel`, enabling fast local execution via `swift test` and automated CI verification on iOS Simulator. Key Changes: - `IntegrationTestingBackend`: Defines canonical backend configurations (`.developerAPI`, `.firebaseAILogicDeveloperAPI`, and `.firebaseAILogicAgentPlatform`), dynamically resolving endpoints, model resource paths, and auth headers from available credentials. - `IntegrationTestEnvironment`: Centralizes credential discovery (`GEMINI_API_KEY`, `GOOGLE_API_KEY`, and `FIREBASE_PLIST_PATH`) into an immutable, thread-safe configuration struct with cached process access to avoid redundant disk I/O. - `AppCheckDebugClient`: Implements a lightweight client to exchange debug tokens for App Check tokens without Keychain dependencies, deduplicating token requests across test runs with an in-memory cache. - Parameterized Tests: Adds `BasicContentGenerationIntegrationTests` running against all available backends, tagged with `@Tag.integration` and gated by condition traits to cleanly skip when credentials are missing. - CI Workflow: Adds `.github/workflows/sdk.geminilanguagemodel.yml` to run integration tests against Firebase AI Logic on iOS Simulator using decrypted repo secrets.
GeminiTestUtilities
Shared testing infrastructure, network mocking utilities, environment condition
traits, and integration test backends for GeminiLanguageModel and
GeminiAPIClient.
Overview
GeminiTestUtilities is an internal test support target consumed across all
test suites in the package. It provides centralized utilities so tests avoid
duplicating mock handlers, endpoint URLs, credential checks, or port probes.
Component Breakdown
| Category | Files | Purpose |
|---|---|---|
| Network Mocking | MockHTTPURLProtocol.swift, HTTPURLResponse+Mock.swift |
Offline URLSession request interception, response mocking, and SSE streaming simulation |
| Integration Backends | IntegrationTestingBackend.swift, AppCheckDebugClient.swift |
Backend routing configurations, TCP socket probing, App Check debug token exchange and caching |
| Testing Traits & Tags | ConditionTrait+Credentials.swift, ConditionTrait+FoundationModels.swift, Tag+Integration.swift |
Swift Testing conditional skip traits (.requireAPIKey, .requireFoundationModels) and .integration tag |
| Constants | TestConstants.swift |
Centralized model resource IDs and canonical endpoint configurations |
Common Recipes
1. Mocking HTTP URL Responses
Use MockHTTPURLProtocol and HTTPURLResponse.mock to simulate API responses
without network access:
defer { MockHTTPURLProtocol.reset() }
let expectedURL = URL(string: "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash-lite:generateContent")!
let response = try HTTPURLResponse.mock(url: expectedURL, statusCode: 200)
MockHTTPURLProtocol.setHandler(for: expectedURL) { request, proto in
proto.client?.urlProtocol(proto, didReceive: response, cacheStoragePolicy: .notAllowed)
proto.client?.urlProtocol(proto, didLoad: Data("{}".utf8))
proto.client?.urlProtocolDidFinishLoading(proto)
}
2. Guarding Tests with Condition Traits
Swift Testing condition traits allow tests to cleanly skip when prerequisites (like API keys or specific OS versions) are absent:
// Skip if neither local test-server nor remote credentials are available
@Test(.requireIntegrationTestingBackend)
func myBackendTest() async throws { ... }
// Skip on platforms where FoundationModels is unavailable (< macOS 27)
@Suite("Model Tests", .requireFoundationModels)
struct ModelTests { ... }
3. App Check Token Caching
AppCheckTokenCache manages debug token exchange for Firebase AI Logic
integration tests, caching active tokens in-memory and deduplicating in-flight
network requests:
let token = try await AppCheckTokenCache.shared.token(
projectID: projectID,
appID: appID,
apiKey: apiKey,
debugToken: debugToken
)