From 17ec791bfedba3372916cf30fe8755c2e9bd8d78 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 20 Mar 2025 14:22:33 -0400 Subject: [PATCH 1/4] [Vertex AI] Swift Testing `testGenerateContentStream` integration test --- .../GenerateContentIntegrationTests.swift | 45 +++++++++++++++++++ .../Tests/Integration/IntegrationTests.swift | 39 ---------------- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 92ebe09d159..3761471d5a1 100644 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -115,4 +115,49 @@ struct GenerateContentIntegrationTests { #expect(candidatesTokensDetails.modality == .text) #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) } + + @Test(arguments: InstanceConfig.allConfigs) + func testGenerateContentStream(_ config: InstanceConfig) async throws { + let expectedText = """ + 1. Mercury + 2. Venus + 3. Earth + 4. Mars + 5. Jupiter + 6. Saturn + 7. Uranus + 8. Neptune + """ + let prompt = """ + What are the names of the planets in the solar system, ordered from closest to furthest from + the sun? Answer with a Markdown numbered list of the names and no other text. + """ + let model = VertexAI.componentInstance(config).generativeModel( + modelName: ModelNames.gemini2FlashLite, + generationConfig: generationConfig, + safetySettings: safetySettings + ) + let chat = model.startChat() + + let stream = try chat.sendMessageStream(prompt) + var textValues = [String]() + for try await value in stream { + try textValues.append(#require(value.text)) + } + + let userHistory = try #require(chat.history.first) + #expect(userHistory.role == "user") + #expect(userHistory.parts.count == 1) + let promptTextPart = try #require(userHistory.parts.first as? TextPart) + #expect(promptTextPart.text == prompt) + let modelHistory = try #require(chat.history.last) + #expect(modelHistory.role == "model") + #expect(modelHistory.parts.count == 1) + let modelTextPart = try #require(modelHistory.parts.first as? TextPart) + let modelText = modelTextPart.text.trimmingCharacters(in: .whitespacesAndNewlines) + #expect(modelText == expectedText) + #expect(textValues.count > 1) + let text = textValues.joined().trimmingCharacters(in: .whitespacesAndNewlines) + #expect(text == expectedText) + } } diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index 4bac229088e..1758dbdde26 100644 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -69,45 +69,6 @@ final class IntegrationTests: XCTestCase { // MARK: - Generate Content - func testGenerateContentStream() async throws { - let expectedText = """ - 1. Mercury - 2. Venus - 3. Earth - 4. Mars - 5. Jupiter - 6. Saturn - 7. Uranus - 8. Neptune - """ - let prompt = """ - What are the names of the planets in the solar system, ordered from closest to furthest from - the sun? Answer with a Markdown numbered list of the names and no other text. - """ - let chat = model.startChat() - - let stream = try chat.sendMessageStream(prompt) - var textValues = [String]() - for try await value in stream { - try textValues.append(XCTUnwrap(value.text)) - } - - let userHistory = try XCTUnwrap(chat.history.first) - XCTAssertEqual(userHistory.role, "user") - XCTAssertEqual(userHistory.parts.count, 1) - let promptTextPart = try XCTUnwrap(userHistory.parts.first as? TextPart) - XCTAssertEqual(promptTextPart.text, prompt) - let modelHistory = try XCTUnwrap(chat.history.last) - XCTAssertEqual(modelHistory.role, "model") - XCTAssertEqual(modelHistory.parts.count, 1) - let modelTextPart = try XCTUnwrap(modelHistory.parts.first as? TextPart) - let modelText = modelTextPart.text.trimmingCharacters(in: .whitespacesAndNewlines) - XCTAssertEqual(modelText, expectedText) - XCTAssertGreaterThan(textValues.count, 1) - let text = textValues.joined().trimmingCharacters(in: .whitespacesAndNewlines) - XCTAssertEqual(text, expectedText) - } - func testGenerateContent_appCheckNotConfigured_shouldFail() async throws { let app = try FirebaseApp.defaultNamedCopy(name: FirebaseAppNames.appCheckNotConfigured) addTeardownBlock { await app.delete() } From ecfd28321b84ee14695ee7338dd2190257d6d8ac Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 24 Mar 2025 16:10:18 -0400 Subject: [PATCH 2/4] Migrate App Check not configured integration test for `generateContent` --- .../TestApp/Sources/FirebaseAppUtils.swift | 28 +++++++++++++++ .../Tests/TestApp/Sources/TestApp.swift | 15 ++++---- .../GenerateContentIntegrationTests.swift | 34 ++++++++++++++++++- .../Tests/Integration/IntegrationTests.swift | 17 ---------- .../Tests/Utilities/InstanceConfig.swift | 9 +++++ .../VertexAITestApp.xcodeproj/project.pbxproj | 4 +++ 6 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift diff --git a/FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift b/FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift new file mode 100644 index 00000000000..a846bfbda64 --- /dev/null +++ b/FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift @@ -0,0 +1,28 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FirebaseCore + +extension FirebaseApp { + static func configure(appName: String, plistName: String) { + guard let plistPath = + Bundle.main.path(forResource: plistName, ofType: "plist") else { + fatalError("The file '\(plistName).plist' was not found.") + } + guard let options = FirebaseOptions(contentsOfFile: plistPath) else { + fatalError("Failed to parse options from '\(plistName).plist'.") + } + FirebaseApp.configure(name: appName, options: options) + } +} diff --git a/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift b/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift index b466503417d..639f6c89f77 100644 --- a/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift +++ b/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift @@ -24,15 +24,14 @@ struct TestApp: App { // Configure default Firebase App FirebaseApp.configure() + // Configure a Firebase App that is the same as the default app but without App Check. + FirebaseApp.configure( + appName: FirebaseAppNames.appCheckNotConfigured, + plistName: "GoogleService-Info" + ) + // Configure a Firebase App without a billing account (i.e., the "Spark" plan). - guard let plistPath = - Bundle.main.path(forResource: "GoogleService-Info-Spark", ofType: "plist") else { - fatalError("The file 'GoogleService-Info-Spark.plist' was not found.") - } - guard let options = FirebaseOptions(contentsOfFile: plistPath) else { - fatalError("Failed to parse options from 'GoogleService-Info-Spark.plist'.") - } - FirebaseApp.configure(name: FirebaseAppNames.spark, options: options) + FirebaseApp.configure(appName: FirebaseAppNames.spark, plistName: "GoogleService-Info-Spark") } var body: some Scene { diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index 3761471d5a1..f22ce23631e 100644 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -116,8 +116,10 @@ struct GenerateContentIntegrationTests { #expect(candidatesTokensDetails.tokenCount == usageMetadata.candidatesTokenCount) } + // MARK: Streaming Tests + @Test(arguments: InstanceConfig.allConfigs) - func testGenerateContentStream(_ config: InstanceConfig) async throws { + func generateContentStream(_ config: InstanceConfig) async throws { let expectedText = """ 1. Mercury 2. Venus @@ -160,4 +162,34 @@ struct GenerateContentIntegrationTests { let text = textValues.joined().trimmingCharacters(in: .whitespacesAndNewlines) #expect(text == expectedText) } + + // MARK: - App Check Tests + + @Test(arguments: [ + InstanceConfig.vertexV1AppCheckNotConfigured, + InstanceConfig.vertexV1BetaAppCheckNotConfigured, + // App Check is not supported on the Generative Language Developer API endpoint since it + // bypasses the Vertex AI in Firebase proxy. + ]) + func generateContent_appCheckNotConfigured_shouldFail(_ config: InstanceConfig) async throws { + let model = VertexAI.componentInstance(config).generativeModel( + modelName: ModelNames.gemini2Flash + ) + let prompt = "Where is Google headquarters located? Answer with the city name only." + + try await #require { + _ = try await model.generateContent(prompt) + } throws: { + guard let error = $0 as? GenerateContentError else { + Issue.record("Expected a \(GenerateContentError.self); got \($0.self).") + return false + } + guard case let .internalError(underlyingError) = error else { + Issue.record("Expected a \(GenerateContentError.internalError.self); got \(error.self).") + return false + } + + return String(describing: underlyingError).contains("Firebase App Check token is invalid") + } + } } diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index 1758dbdde26..8acb0ea0988 100644 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -67,23 +67,6 @@ final class IntegrationTests: XCTestCase { storage = Storage.storage() } - // MARK: - Generate Content - - func testGenerateContent_appCheckNotConfigured_shouldFail() async throws { - let app = try FirebaseApp.defaultNamedCopy(name: FirebaseAppNames.appCheckNotConfigured) - addTeardownBlock { await app.delete() } - let vertex = VertexAI.vertexAI(app: app) - let model = vertex.generativeModel(modelName: "gemini-2.0-flash") - let prompt = "Where is Google headquarters located? Answer with the city name only." - - do { - _ = try await model.generateContent(prompt) - XCTFail("Expected a Firebase App Check error; none thrown.") - } catch let GenerateContentError.internalError(error) { - XCTAssertTrue(String(describing: error).contains("Firebase App Check token is invalid")) - } - } - // MARK: - Count Tokens func testCountTokens_text() async throws { diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift index 7c233e94f7a..0c1a3728673 100644 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift +++ b/FirebaseVertexAI/Tests/TestApp/Tests/Utilities/InstanceConfig.swift @@ -34,6 +34,15 @@ struct InstanceConfig { ) static let allConfigs = [vertexV1, vertexV1Beta, developerV1, developerV1Beta] + static let vertexV1AppCheckNotConfigured = InstanceConfig( + appName: FirebaseAppNames.appCheckNotConfigured, + apiConfig: APIConfig(service: .vertexAI, version: .v1) + ) + static let vertexV1BetaAppCheckNotConfigured = InstanceConfig( + appName: FirebaseAppNames.appCheckNotConfigured, + apiConfig: APIConfig(service: .vertexAI, version: .v1beta) + ) + let appName: String? let location: String? let apiConfig: APIConfig diff --git a/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj b/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj index 6f13a62472e..b873dde1689 100644 --- a/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj +++ b/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 8692F29E2CC9477800539E8F /* FirebaseVertexAI in Frameworks */ = {isa = PBXBuildFile; productRef = 8692F29D2CC9477800539E8F /* FirebaseVertexAI */; }; 8698D7462CD3CF3600ABA833 /* FirebaseAppTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698D7452CD3CF2F00ABA833 /* FirebaseAppTestUtils.swift */; }; 8698D7482CD4332B00ABA833 /* TestAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698D7472CD4332B00ABA833 /* TestAppCheckProviderFactory.swift */; }; + 86CC31352D91EE9E0087E964 /* FirebaseAppUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86CC31342D91EE9E0087E964 /* FirebaseAppUtils.swift */; }; 86D77DFC2D7A5340003D155D /* GenerateContentIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86D77DFB2D7A5340003D155D /* GenerateContentIntegrationTests.swift */; }; 86D77DFE2D7B5C86003D155D /* GoogleService-Info-Spark.plist in Resources */ = {isa = PBXBuildFile; fileRef = 86D77DFD2D7B5C86003D155D /* GoogleService-Info-Spark.plist */; }; 86D77E022D7B63AF003D155D /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86D77E012D7B63AC003D155D /* Constants.swift */; }; @@ -55,6 +56,7 @@ 868A7C552CCC271300E449DD /* TestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TestApp.entitlements; sourceTree = ""; }; 8698D7452CD3CF2F00ABA833 /* FirebaseAppTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseAppTestUtils.swift; sourceTree = ""; }; 8698D7472CD4332B00ABA833 /* TestAppCheckProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAppCheckProviderFactory.swift; sourceTree = ""; }; + 86CC31342D91EE9E0087E964 /* FirebaseAppUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseAppUtils.swift; sourceTree = ""; }; 86D77DFB2D7A5340003D155D /* GenerateContentIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateContentIntegrationTests.swift; sourceTree = ""; }; 86D77DFD2D7B5C86003D155D /* GoogleService-Info-Spark.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info-Spark.plist"; sourceTree = ""; }; 86D77E012D7B63AC003D155D /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; @@ -129,6 +131,7 @@ 8698D7472CD4332B00ABA833 /* TestAppCheckProviderFactory.swift */, 8661385D2CC943DD00F4B78E /* ContentView.swift */, 86D77E012D7B63AC003D155D /* Constants.swift */, + 86CC31342D91EE9E0087E964 /* FirebaseAppUtils.swift */, ); path = Sources; sourceTree = ""; @@ -275,6 +278,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 86CC31352D91EE9E0087E964 /* FirebaseAppUtils.swift in Sources */, 8661385E2CC943DD00F4B78E /* ContentView.swift in Sources */, 8661385C2CC943DD00F4B78E /* TestApp.swift in Sources */, 8698D7482CD4332B00ABA833 /* TestAppCheckProviderFactory.swift in Sources */, From d983bcf685b32157e3ea7949cc71b0e6234c138d Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 24 Mar 2025 18:48:20 -0400 Subject: [PATCH 3/4] Fix `App named app-check-not-configured has already been configured` error --- .../TestApp/Sources/FirebaseAppUtils.swift | 9 +++++ .../GenerateContentIntegrationTests.swift | 2 +- .../Tests/Integration/IntegrationTests.swift | 3 +- .../Utilities/FirebaseAppTestUtils.swift | 40 ------------------- .../VertexAITestApp.xcodeproj/project.pbxproj | 4 -- 5 files changed, 11 insertions(+), 47 deletions(-) delete mode 100644 FirebaseVertexAI/Tests/TestApp/Tests/Utilities/FirebaseAppTestUtils.swift diff --git a/FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift b/FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift index a846bfbda64..fc32065d2bf 100644 --- a/FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift +++ b/FirebaseVertexAI/Tests/TestApp/Sources/FirebaseAppUtils.swift @@ -15,7 +15,16 @@ import FirebaseCore extension FirebaseApp { + /// Configures a Firebase app with the specified name and Google Service Info plist file name. + /// + /// - Parameters: + /// - appName: The Firebase app's name; see ``FirebaseAppNames`` for app names with special + /// meanings in the TestApp. + /// - plistName: The file name of the Google Service Info plist, excluding the file extension; + /// for the default app this is typically called `GoogleService-Info` but any file name may be + /// used for other apps. static func configure(appName: String, plistName: String) { + assert(!plistName.hasSuffix(".plist"), "The .plist file extension must be omitted.") guard let plistPath = Bundle.main.path(forResource: plistName, ofType: "plist") else { fatalError("The file '\(plistName).plist' was not found.") diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift index f22ce23631e..d0c6ca3f5bd 100644 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift +++ b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift @@ -185,7 +185,7 @@ struct GenerateContentIntegrationTests { return false } guard case let .internalError(underlyingError) = error else { - Issue.record("Expected a \(GenerateContentError.internalError.self); got \(error.self).") + Issue.record("Expected a GenerateContentError.internalError(...); got \(error.self).") return false } diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift index 8acb0ea0988..e3da2d07496 100644 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift +++ b/FirebaseVertexAI/Tests/TestApp/Tests/Integration/IntegrationTests.swift @@ -229,8 +229,7 @@ final class IntegrationTests: XCTestCase { } func testCountTokens_appCheckNotConfigured_shouldFail() async throws { - let app = try FirebaseApp.defaultNamedCopy(name: FirebaseAppNames.appCheckNotConfigured) - addTeardownBlock { await app.delete() } + let app = try XCTUnwrap(FirebaseApp.app(name: FirebaseAppNames.appCheckNotConfigured)) let vertex = VertexAI.vertexAI(app: app) let model = vertex.generativeModel(modelName: "gemini-2.0-flash") let prompt = "Why is the sky blue?" diff --git a/FirebaseVertexAI/Tests/TestApp/Tests/Utilities/FirebaseAppTestUtils.swift b/FirebaseVertexAI/Tests/TestApp/Tests/Utilities/FirebaseAppTestUtils.swift deleted file mode 100644 index 5bd0fbec1e7..00000000000 --- a/FirebaseVertexAI/Tests/TestApp/Tests/Utilities/FirebaseAppTestUtils.swift +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import FirebaseCore - -extension FirebaseApp { - /// Configures another `FirebaseApp` with the specified `name` and the same `FirebaseOptions`. - func namedCopy(name: String) throws -> FirebaseApp { - FirebaseApp.configure(name: name, options: options) - guard let app = FirebaseApp.app(name: name) else { - throw AppNotFound(name: name) - } - return app - } - - /// Configures an app with the specified `name` and the same `FirebaseOptions` as the default app. - static func defaultNamedCopy(name: String) throws -> FirebaseApp { - guard FirebaseApp.isDefaultAppConfigured(), let defaultApp = FirebaseApp.app() else { - throw DefaultAppNotConfigured() - } - return try defaultApp.namedCopy(name: name) - } - - struct AppNotFound: Error { - let name: String - } - - struct DefaultAppNotConfigured: Error {} -} diff --git a/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj b/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj index b873dde1689..0012ad35261 100644 --- a/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj +++ b/FirebaseVertexAI/Tests/TestApp/VertexAITestApp.xcodeproj/project.pbxproj @@ -21,7 +21,6 @@ 8692F29A2CC9477800539E8F /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 8692F2992CC9477800539E8F /* FirebaseAuth */; }; 8692F29C2CC9477800539E8F /* FirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 8692F29B2CC9477800539E8F /* FirebaseStorage */; }; 8692F29E2CC9477800539E8F /* FirebaseVertexAI in Frameworks */ = {isa = PBXBuildFile; productRef = 8692F29D2CC9477800539E8F /* FirebaseVertexAI */; }; - 8698D7462CD3CF3600ABA833 /* FirebaseAppTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698D7452CD3CF2F00ABA833 /* FirebaseAppTestUtils.swift */; }; 8698D7482CD4332B00ABA833 /* TestAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698D7472CD4332B00ABA833 /* TestAppCheckProviderFactory.swift */; }; 86CC31352D91EE9E0087E964 /* FirebaseAppUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86CC31342D91EE9E0087E964 /* FirebaseAppUtils.swift */; }; 86D77DFC2D7A5340003D155D /* GenerateContentIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86D77DFB2D7A5340003D155D /* GenerateContentIntegrationTests.swift */; }; @@ -54,7 +53,6 @@ 868A7C502CCC263300E449DD /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 868A7C532CCC26B500E449DD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 868A7C552CCC271300E449DD /* TestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TestApp.entitlements; sourceTree = ""; }; - 8698D7452CD3CF2F00ABA833 /* FirebaseAppTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseAppTestUtils.swift; sourceTree = ""; }; 8698D7472CD4332B00ABA833 /* TestAppCheckProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAppCheckProviderFactory.swift; sourceTree = ""; }; 86CC31342D91EE9E0087E964 /* FirebaseAppUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseAppUtils.swift; sourceTree = ""; }; 86D77DFB2D7A5340003D155D /* GenerateContentIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateContentIntegrationTests.swift; sourceTree = ""; }; @@ -161,7 +159,6 @@ isa = PBXGroup; children = ( 86D77E032D7B6C95003D155D /* InstanceConfig.swift */, - 8698D7452CD3CF2F00ABA833 /* FirebaseAppTestUtils.swift */, 862218802D04E08D007ED2D4 /* IntegrationTestUtils.swift */, ); path = Utilities; @@ -292,7 +289,6 @@ files = ( 8689CDCC2D7F8BD700BF426B /* CountTokensIntegrationTests.swift in Sources */, 86D77E042D7B6C9D003D155D /* InstanceConfig.swift in Sources */, - 8698D7462CD3CF3600ABA833 /* FirebaseAppTestUtils.swift in Sources */, 868A7C4F2CCC229F00E449DD /* Credentials.swift in Sources */, 864F8F712D4980DD0002EA7E /* ImagenIntegrationTests.swift in Sources */, 862218812D04E098007ED2D4 /* IntegrationTestUtils.swift in Sources */, From 3d08322453751b9c90237fd9109ea7223a4a03ce Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Mon, 24 Mar 2025 19:03:26 -0400 Subject: [PATCH 4/4] Add explanation for FirebaseApp without App Check --- FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift b/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift index 639f6c89f77..d1424111769 100644 --- a/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift +++ b/FirebaseVertexAI/Tests/TestApp/Sources/TestApp.swift @@ -25,6 +25,7 @@ struct TestApp: App { FirebaseApp.configure() // Configure a Firebase App that is the same as the default app but without App Check. + // This is used for tests that should fail when App Check is not configured. FirebaseApp.configure( appName: FirebaseAppNames.appCheckNotConfigured, plistName: "GoogleService-Info"