Files
firebase-ios-sdk/FirebaseAI/Tests/Unit/VertexComponentTests.swift
T

270 lines
10 KiB
Swift

// 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.
@preconcurrency import FirebaseCore
internal import FirebaseCoreExtension
import Foundation
import XCTest
@testable import FirebaseAI
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
class VertexComponentTests: XCTestCase {
static let projectID = "test-project-id"
static let apiKey = "test-api-key"
static let options = {
let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
gcmSenderID: "00000000000000000-00000000000-000000000")
options.projectID = VertexComponentTests.projectID
options.apiKey = VertexComponentTests.apiKey
return options
}()
static let app = FirebaseApp(instanceWithName: "test", options: options)
let location = "test-location"
let modelName = "test-model-name"
let systemInstruction = ModelContent(role: "system", parts: "test-system-instruction-prompt")
override class func setUp() {
FirebaseApp.configure(options: options)
guard FirebaseApp.app() != nil else {
fatalError("The default app does not exist.")
}
}
/// Test that the objc class is available for the component system to update the user agent.
func testComponentsBeingRegistered() throws {
XCTAssertNotNil(NSClassFromString("FIRVertexAIComponent"))
}
/// Tests that a vertex instance can be created properly using the default Firebase app.
func testVertexInstanceCreation_defaultApp() throws {
let vertex = FirebaseAI.firebaseAI(backend: .vertexAI())
XCTAssertNotNil(vertex)
XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID)
XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey)
XCTAssertEqual(vertex.location, "us-central1")
XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd))
XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd)
XCTAssertEqual(vertex.apiConfig.version, .v1beta)
}
/// Tests that a vertex instance can be created properly using the default Firebase app and custom
/// location.
func testVertexInstanceCreation_defaultApp_customLocation() throws {
let vertex = FirebaseAI.firebaseAI(backend: .vertexAI(location: location))
XCTAssertNotNil(vertex)
XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID)
XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey)
XCTAssertEqual(vertex.location, location)
XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd))
XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd)
XCTAssertEqual(vertex.apiConfig.version, .v1beta)
}
/// Tests that a vertex instance can be created properly.
func testVertexInstanceCreation_customApp() throws {
let vertex = FirebaseAI.firebaseAI(
app: VertexComponentTests.app,
backend: .vertexAI(location: location)
)
XCTAssertNotNil(vertex)
XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID)
XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey)
XCTAssertEqual(vertex.location, location)
XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd))
XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd)
XCTAssertEqual(vertex.apiConfig.version, .v1beta)
}
/// Tests that Vertex instances are reused properly.
func testSameAppAndLocation_instanceReused() throws {
let app = try XCTUnwrap(VertexComponentTests.app)
let vertex1 = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
let vertex2 = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
// Ensure they're the same instance.
XCTAssert(vertex1 === vertex2)
}
func testSameAppAndDifferentLocation_newInstanceCreated() throws {
let vertex1 = FirebaseAI.firebaseAI(
app: VertexComponentTests.app,
backend: .vertexAI(location: location)
)
let vertex2 = FirebaseAI.firebaseAI(
app: VertexComponentTests.app,
backend: .vertexAI(location: "differentLocation")
)
// Ensure they are different instances.
XCTAssert(vertex1 !== vertex2)
}
func testDifferentAppAndSameLocation_newInstanceCreated() throws {
FirebaseApp.configure(name: "test-2", options: VertexComponentTests.options)
let app2 = FirebaseApp(instanceWithName: "test-2", options: VertexComponentTests.options)
addTeardownBlock { await app2.delete() }
let vertex1 = FirebaseAI.firebaseAI(
app: VertexComponentTests.app,
backend: .vertexAI(location: location)
)
let vertex2 = FirebaseAI.firebaseAI(app: app2, backend: .vertexAI(location: location))
XCTAssert(VertexComponentTests.app != app2)
XCTAssert(vertex1 !== vertex2) // Ensure they are different instances.
}
func testDifferentAppAndDifferentLocation_newInstanceCreated() throws {
FirebaseApp.configure(name: "test-2", options: VertexComponentTests.options)
let app2 = FirebaseApp(instanceWithName: "test-2", options: VertexComponentTests.options)
addTeardownBlock { await app2.delete() }
let vertex1 = FirebaseAI.firebaseAI(
app: VertexComponentTests.app,
backend: .vertexAI(location: location)
)
let vertex2 = FirebaseAI.firebaseAI(
app: app2,
backend: .vertexAI(location: "differentLocation")
)
XCTAssert(VertexComponentTests.app != app2)
XCTAssert(vertex1 !== vertex2) // Ensure they are different instances.
}
func testSameAppAndDifferentAPI_newInstanceCreated() throws {
let vertex1 = FirebaseAI.createInstance(
app: VertexComponentTests.app,
location: location,
apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta)
)
let vertex2 = FirebaseAI.createInstance(
app: VertexComponentTests.app,
location: location,
apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1)
)
// Ensure they are different instances.
XCTAssert(vertex1 !== vertex2)
}
/// Test that vertex instances get deallocated.
func testVertexLifecycle() throws {
weak var weakApp: FirebaseApp?
weak var weakVertex: FirebaseAI?
try autoreleasepool {
let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
gcmSenderID: "00000000000000000-00000000000-000000000")
options.projectID = VertexComponentTests.projectID
options.apiKey = VertexComponentTests.apiKey
let app1 = FirebaseApp(instanceWithName: "transitory app", options: options)
weakApp = try XCTUnwrap(app1)
let vertex = FirebaseAI(
app: app1,
location: "transitory location",
apiConfig: FirebaseAI.defaultVertexAIAPIConfig
)
weakVertex = vertex
XCTAssertNotNil(weakVertex)
}
XCTAssertNil(weakApp)
XCTAssertNil(weakVertex)
}
func testModelResourceName_vertexAI() throws {
let app = try XCTUnwrap(VertexComponentTests.app)
let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
let model = "test-model-name"
let projectID = vertex.firebaseInfo.projectID
let modelResourceName = vertex.modelResourceName(modelName: model)
let location = try XCTUnwrap(vertex.location)
XCTAssertEqual(
modelResourceName,
"projects/\(projectID)/locations/\(location)/publishers/google/models/\(model)"
)
}
func testModelResourceName_developerAPI_generativeLanguage() throws {
let app = try XCTUnwrap(VertexComponentTests.app)
let apiConfig = APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta)
let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig)
let model = "test-model-name"
let modelResourceName = vertex.modelResourceName(modelName: model)
XCTAssertEqual(modelResourceName, "models/\(model)")
}
func testModelResourceName_developerAPI_firebaseVertexAI() throws {
let app = try XCTUnwrap(VertexComponentTests.app)
let apiConfig = APIConfig(
service: .googleAI(endpoint: .firebaseProxyStaging),
version: .v1beta
)
let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig)
let model = "test-model-name"
let projectID = vertex.firebaseInfo.projectID
let modelResourceName = vertex.modelResourceName(modelName: model)
XCTAssertEqual(modelResourceName, "projects/\(projectID)/models/\(model)")
}
func testGenerativeModel_vertexAI() async throws {
let app = try XCTUnwrap(VertexComponentTests.app)
let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
let modelResourceName = vertex.modelResourceName(modelName: modelName)
let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts)
let generativeModel = vertex.generativeModel(
modelName: modelName,
systemInstruction: systemInstruction
)
XCTAssertEqual(generativeModel.modelResourceName, modelResourceName)
XCTAssertEqual(generativeModel.systemInstruction, expectedSystemInstruction)
XCTAssertEqual(generativeModel.apiConfig, FirebaseAI.defaultVertexAIAPIConfig)
}
func testGenerativeModel_developerAPI() async throws {
let app = try XCTUnwrap(VertexComponentTests.app)
let apiConfig = APIConfig(
service: .googleAI(endpoint: .firebaseProxyStaging),
version: .v1beta
)
let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig)
let modelResourceName = vertex.modelResourceName(modelName: modelName)
let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts)
let generativeModel = vertex.generativeModel(
modelName: modelName,
systemInstruction: systemInstruction
)
XCTAssertEqual(generativeModel.modelResourceName, modelResourceName)
XCTAssertEqual(generativeModel.systemInstruction, expectedSystemInstruction)
XCTAssertEqual(generativeModel.apiConfig, apiConfig)
}
}