diff --git a/FirebaseVertexAI.podspec b/FirebaseVertexAI.podspec index f435ff4b9bf..2b58577bd76 100644 --- a/FirebaseVertexAI.podspec +++ b/FirebaseVertexAI.podspec @@ -61,7 +61,7 @@ Firebase SDK. unit_tests_dir + '**/*.swift', ] unit_tests.resources = [ - unit_tests_dir + 'vertexai-sdk-test-data/mock-responses/**/*.{txt,json}', + unit_tests_dir + 'vertexai-sdk-test-data/mock-responses/vertexai', unit_tests_dir + 'Resources/**/*', ] end diff --git a/FirebaseVertexAI/Tests/Unit/ChatTests.swift b/FirebaseVertexAI/Tests/Unit/ChatTests.swift index 4e8a1ae0f73..3dceb01837e 100644 --- a/FirebaseVertexAI/Tests/Unit/ChatTests.swift +++ b/FirebaseVertexAI/Tests/Unit/ChatTests.swift @@ -36,7 +36,8 @@ final class ChatTests: XCTestCase { let bundle = BundleTestUtil.bundle() let fileURL = try XCTUnwrap(bundle.url( forResource: "streaming-success-basic-reply-parts", - withExtension: "txt" + withExtension: "txt", + subdirectory: "vertexai" )) // Skip tests using MockURLProtocol on watchOS; unsupported in watchOS 2 and later, see diff --git a/FirebaseVertexAI/Tests/Unit/GenerativeModelTests.swift b/FirebaseVertexAI/Tests/Unit/GenerativeModelTests.swift index 891e4bc359e..244724f32c6 100644 --- a/FirebaseVertexAI/Tests/Unit/GenerativeModelTests.swift +++ b/FirebaseVertexAI/Tests/Unit/GenerativeModelTests.swift @@ -60,6 +60,8 @@ final class GenerativeModelTests: XCTestCase { "projects/test-project-id/locations/test-location/publishers/google/models/test-model" let apiConfig = APIConfig(service: .vertexAI, version: .v1beta) + let vertexSubdirectory = "vertexai" + var urlSession: URLSession! var model: GenerativeModel! @@ -87,7 +89,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-long", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -109,7 +112,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -131,7 +135,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-response-long-usage-metadata", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -155,7 +160,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-citations", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let expectedPublicationDate = DateComponents( calendar: Calendar(identifier: .gregorian), @@ -199,7 +205,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-quote-reply", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -249,7 +256,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-unknown-enum-safety-ratings", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -263,7 +271,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let model = GenerativeModel( // Model name is prefixed with "models/". @@ -282,7 +291,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-function-call-empty-arguments", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -304,7 +314,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-function-call-no-arguments", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -326,7 +337,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-function-call-with-arguments", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -352,7 +364,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-function-call-parallel-calls", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -368,7 +381,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-function-call-mixed-content", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -396,6 +410,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", withExtension: "json", + subdirectory: vertexSubdirectory, appCheckToken: appCheckToken ) @@ -417,6 +432,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", withExtension: "json", + subdirectory: vertexSubdirectory, appCheckToken: appCheckToken, dataCollection: false ) @@ -437,6 +453,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", withExtension: "json", + subdirectory: vertexSubdirectory, appCheckToken: AppCheckInteropFake.placeholderTokenValue ) @@ -457,6 +474,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", withExtension: "json", + subdirectory: vertexSubdirectory, authToken: authToken ) @@ -476,6 +494,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", withExtension: "json", + subdirectory: vertexSubdirectory, authToken: nil ) @@ -495,6 +514,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", withExtension: "json", + subdirectory: vertexSubdirectory, authToken: nil ) @@ -512,7 +532,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.generateContent(testPrompt) @@ -531,6 +552,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-failure-api-key", withExtension: "json", + subdirectory: vertexSubdirectory, statusCode: expectedStatusCode ) @@ -559,6 +581,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-failure-firebasevertexai-api-not-enabled", withExtension: "json", + subdirectory: vertexSubdirectory, statusCode: expectedStatusCode ) @@ -581,7 +604,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-empty-content", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) do { @@ -604,7 +628,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-finish-reason-safety", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) do { @@ -622,7 +647,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-finish-reason-safety-no-content", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) do { @@ -642,6 +668,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-failure-image-rejected", withExtension: "json", + subdirectory: vertexSubdirectory, statusCode: 400 ) @@ -661,7 +688,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-prompt-blocked-safety", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) do { @@ -681,7 +709,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-prompt-blocked-safety-with-message", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) do { @@ -701,7 +730,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-unknown-enum-finish-reason", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let unknownFinishReason = FinishReason(rawValue: "FAKE_NEW_FINISH_REASON") @@ -720,7 +750,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-unknown-enum-prompt-blocked", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let unknownBlockReason = PromptFeedback.BlockReason(rawValue: "FAKE_NEW_BLOCK_REASON") @@ -741,6 +772,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-failure-unknown-model", withExtension: "json", + subdirectory: vertexSubdirectory, statusCode: 404 ) @@ -783,7 +815,8 @@ final class GenerativeModelTests: XCTestCase { func testGenerateContent_failure_invalidResponse() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "unary-failure-invalid-response", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) var responseError: Error? @@ -813,7 +846,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-malformed-content", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) var responseError: Error? @@ -845,7 +879,8 @@ final class GenerativeModelTests: XCTestCase { func testGenerateContentMissingSafetyRatings() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "unary-success-missing-safety-ratings", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let content = try await model.generateContent(testPrompt) @@ -860,6 +895,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-basic-reply-short", withExtension: "json", + subdirectory: vertexSubdirectory, timeout: expectedTimeout ) let requestOptions = RequestOptions(timeout: expectedTimeout) @@ -883,7 +919,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "unary-failure-api-key", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) do { @@ -913,6 +950,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-failure-firebasevertexai-api-not-enabled", withExtension: "json", + subdirectory: vertexSubdirectory, statusCode: expectedStatusCode ) @@ -937,7 +975,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-failure-empty-content", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) do { @@ -957,7 +996,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-failure-finish-reason-safety", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) do { @@ -980,7 +1020,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-failure-prompt-blocked-safety", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) do { @@ -1002,7 +1043,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-failure-prompt-blocked-safety-with-message", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) do { @@ -1024,7 +1066,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-failure-unknown-finish-enum", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) let unknownFinishReason = FinishReason(rawValue: "FAKE_ENUM") @@ -1045,7 +1088,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-success-basic-reply-long", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) var responses = 0 @@ -1062,7 +1106,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-success-basic-reply-short", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) var responses = 0 @@ -1079,7 +1124,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-success-unknown-safety-enum", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) let unknownSafetyRating = SafetyRating( category: HarmCategory(rawValue: "HARM_CATEGORY_DANGEROUS_CONTENT_NEW_ENUM"), @@ -1107,7 +1153,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-success-citations", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) let expectedPublicationDate = DateComponents( calendar: Calendar(identifier: .gregorian), @@ -1168,6 +1215,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "streaming-success-basic-reply-short", withExtension: "txt", + subdirectory: vertexSubdirectory, appCheckToken: appCheckToken ) @@ -1188,6 +1236,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "streaming-success-basic-reply-short", withExtension: "txt", + subdirectory: vertexSubdirectory, appCheckToken: AppCheckInteropFake.placeholderTokenValue ) @@ -1199,7 +1248,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-success-basic-reply-short", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) var responses = [GenerateContentResponse]() @@ -1224,7 +1274,8 @@ final class GenerativeModelTests: XCTestCase { func testGenerateContentStream_errorMidStream() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "streaming-failure-error-mid-stream", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) var responseCount = 0 @@ -1266,7 +1317,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-failure-invalid-json", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) let stream = try model.generateContentStream(testPrompt) @@ -1290,7 +1342,8 @@ final class GenerativeModelTests: XCTestCase { MockURLProtocol .requestHandler = try httpRequestHandler( forResource: "streaming-failure-malformed-content", - withExtension: "txt" + withExtension: "txt", + subdirectory: vertexSubdirectory ) let stream = try model.generateContentStream(testPrompt) @@ -1317,6 +1370,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "streaming-success-basic-reply-short", withExtension: "txt", + subdirectory: vertexSubdirectory, timeout: expectedTimeout ) let requestOptions = RequestOptions(timeout: expectedTimeout) @@ -1344,7 +1398,8 @@ final class GenerativeModelTests: XCTestCase { func testCountTokens_succeeds() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "unary-success-total-tokens", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.countTokens("Why is the sky blue?") @@ -1356,7 +1411,8 @@ final class GenerativeModelTests: XCTestCase { func testCountTokens_succeeds_detailed() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "unary-success-detailed-token-response", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.countTokens("Why is the sky blue?") @@ -1373,7 +1429,8 @@ final class GenerativeModelTests: XCTestCase { func testCountTokens_succeeds_allOptions() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "unary-success-total-tokens", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let generationConfig = GenerationConfig( temperature: 0.5, @@ -1413,7 +1470,8 @@ final class GenerativeModelTests: XCTestCase { func testCountTokens_succeeds_noBillableCharacters() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "unary-success-no-billable-characters", - withExtension: "json" + withExtension: "json", + subdirectory: vertexSubdirectory ) let response = try await model.countTokens(InlineDataPart(data: Data(), mimeType: "image/jpeg")) @@ -1425,6 +1483,7 @@ final class GenerativeModelTests: XCTestCase { func testCountTokens_modelNotFound() async throws { MockURLProtocol.requestHandler = try httpRequestHandler( forResource: "unary-failure-model-not-found", withExtension: "json", + subdirectory: vertexSubdirectory, statusCode: 404 ) @@ -1447,6 +1506,7 @@ final class GenerativeModelTests: XCTestCase { .requestHandler = try httpRequestHandler( forResource: "unary-success-total-tokens", withExtension: "json", + subdirectory: vertexSubdirectory, timeout: expectedTimeout ) let requestOptions = RequestOptions(timeout: expectedTimeout) @@ -1506,6 +1566,7 @@ final class GenerativeModelTests: XCTestCase { private func httpRequestHandler(forResource name: String, withExtension ext: String, + subdirectory subpath: String, statusCode: Int = 200, timeout: TimeInterval = RequestOptions().timeout, appCheckToken: String? = nil, @@ -1520,7 +1581,9 @@ final class GenerativeModelTests: XCTestCase { throw XCTSkip("Custom URL protocols are unsupported in watchOS 2 and later.") #endif // os(watchOS) let bundle = BundleTestUtil.bundle() - let fileURL = try XCTUnwrap(bundle.url(forResource: name, withExtension: ext)) + let fileURL = try XCTUnwrap( + bundle.url(forResource: name, withExtension: ext, subdirectory: subpath) + ) return { request in let requestURL = try XCTUnwrap(request.url) XCTAssertEqual(requestURL.path.occurrenceCount(of: "models/"), 1) diff --git a/Package.swift b/Package.swift index e89aea07d8d..ac3ab317be2 100644 --- a/Package.swift +++ b/Package.swift @@ -1318,7 +1318,7 @@ let package = Package( ], path: "FirebaseVertexAI/Tests/Unit", resources: [ - .process("vertexai-sdk-test-data/mock-responses"), + .copy("vertexai-sdk-test-data/mock-responses/vertexai"), .process("Resources"), ], cSettings: [