VertexComponentTests.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // Copyright 2024 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. @preconcurrency import FirebaseCore
  15. internal import FirebaseCoreExtension
  16. import Foundation
  17. import XCTest
  18. @testable import FirebaseAI
  19. @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
  20. class VertexComponentTests: XCTestCase {
  21. static let projectID = "test-project-id"
  22. static let apiKey = "test-api-key"
  23. static let options = {
  24. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  25. gcmSenderID: "00000000000000000-00000000000-000000000")
  26. options.projectID = VertexComponentTests.projectID
  27. options.apiKey = VertexComponentTests.apiKey
  28. return options
  29. }()
  30. static let app = FirebaseApp(instanceWithName: "test", options: options)
  31. let location = "test-location"
  32. let modelName = "test-model-name"
  33. let systemInstruction = ModelContent(role: "system", parts: "test-system-instruction-prompt")
  34. override class func setUp() {
  35. FirebaseApp.configure(options: options)
  36. guard FirebaseApp.app() != nil else {
  37. fatalError("The default app does not exist.")
  38. }
  39. }
  40. /// Test that the objc class is available for the component system to update the user agent.
  41. func testComponentsBeingRegistered() throws {
  42. XCTAssertNotNil(NSClassFromString("FIRVertexAIComponent"))
  43. }
  44. /// Tests that a vertex instance can be created properly using the default Firebase app.
  45. func testVertexInstanceCreation_defaultApp() throws {
  46. let vertex = FirebaseAI.firebaseAI(backend: .vertexAI())
  47. XCTAssertNotNil(vertex)
  48. XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID)
  49. XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey)
  50. XCTAssertEqual(vertex.location, "us-central1")
  51. XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd))
  52. XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd)
  53. XCTAssertEqual(vertex.apiConfig.version, .v1beta)
  54. }
  55. /// Tests that a vertex instance can be created properly using the default Firebase app and custom
  56. /// location.
  57. func testVertexInstanceCreation_defaultApp_customLocation() throws {
  58. let vertex = FirebaseAI.firebaseAI(backend: .vertexAI(location: location))
  59. XCTAssertNotNil(vertex)
  60. XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID)
  61. XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey)
  62. XCTAssertEqual(vertex.location, location)
  63. XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd))
  64. XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd)
  65. XCTAssertEqual(vertex.apiConfig.version, .v1beta)
  66. }
  67. /// Tests that a vertex instance can be created properly.
  68. func testVertexInstanceCreation_customApp() throws {
  69. let vertex = FirebaseAI.firebaseAI(
  70. app: VertexComponentTests.app,
  71. backend: .vertexAI(location: location)
  72. )
  73. XCTAssertNotNil(vertex)
  74. XCTAssertEqual(vertex.firebaseInfo.projectID, VertexComponentTests.projectID)
  75. XCTAssertEqual(vertex.firebaseInfo.apiKey, VertexComponentTests.apiKey)
  76. XCTAssertEqual(vertex.location, location)
  77. XCTAssertEqual(vertex.apiConfig.service, .vertexAI(endpoint: .firebaseProxyProd))
  78. XCTAssertEqual(vertex.apiConfig.service.endpoint, .firebaseProxyProd)
  79. XCTAssertEqual(vertex.apiConfig.version, .v1beta)
  80. }
  81. /// Tests that Vertex instances are reused properly.
  82. func testSameAppAndLocation_instanceReused() throws {
  83. let app = try XCTUnwrap(VertexComponentTests.app)
  84. let vertex1 = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
  85. let vertex2 = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
  86. // Ensure they're the same instance.
  87. XCTAssert(vertex1 === vertex2)
  88. }
  89. func testSameAppAndDifferentLocation_newInstanceCreated() throws {
  90. let vertex1 = FirebaseAI.firebaseAI(
  91. app: VertexComponentTests.app,
  92. backend: .vertexAI(location: location)
  93. )
  94. let vertex2 = FirebaseAI.firebaseAI(
  95. app: VertexComponentTests.app,
  96. backend: .vertexAI(location: "differentLocation")
  97. )
  98. // Ensure they are different instances.
  99. XCTAssert(vertex1 !== vertex2)
  100. }
  101. func testDifferentAppAndSameLocation_newInstanceCreated() throws {
  102. FirebaseApp.configure(name: "test-2", options: VertexComponentTests.options)
  103. let app2 = FirebaseApp(instanceWithName: "test-2", options: VertexComponentTests.options)
  104. addTeardownBlock { await app2.delete() }
  105. let vertex1 = FirebaseAI.firebaseAI(
  106. app: VertexComponentTests.app,
  107. backend: .vertexAI(location: location)
  108. )
  109. let vertex2 = FirebaseAI.firebaseAI(app: app2, backend: .vertexAI(location: location))
  110. XCTAssert(VertexComponentTests.app != app2)
  111. XCTAssert(vertex1 !== vertex2) // Ensure they are different instances.
  112. }
  113. func testDifferentAppAndDifferentLocation_newInstanceCreated() throws {
  114. FirebaseApp.configure(name: "test-2", options: VertexComponentTests.options)
  115. let app2 = FirebaseApp(instanceWithName: "test-2", options: VertexComponentTests.options)
  116. addTeardownBlock { await app2.delete() }
  117. let vertex1 = FirebaseAI.firebaseAI(
  118. app: VertexComponentTests.app,
  119. backend: .vertexAI(location: location)
  120. )
  121. let vertex2 = FirebaseAI.firebaseAI(
  122. app: app2,
  123. backend: .vertexAI(location: "differentLocation")
  124. )
  125. XCTAssert(VertexComponentTests.app != app2)
  126. XCTAssert(vertex1 !== vertex2) // Ensure they are different instances.
  127. }
  128. func testSameAppAndDifferentAPI_newInstanceCreated() throws {
  129. let vertex1 = FirebaseAI.createInstance(
  130. app: VertexComponentTests.app,
  131. location: location,
  132. apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1beta)
  133. )
  134. let vertex2 = FirebaseAI.createInstance(
  135. app: VertexComponentTests.app,
  136. location: location,
  137. apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1)
  138. )
  139. // Ensure they are different instances.
  140. XCTAssert(vertex1 !== vertex2)
  141. }
  142. /// Test that vertex instances get deallocated.
  143. func testVertexLifecycle() throws {
  144. weak var weakApp: FirebaseApp?
  145. weak var weakVertex: FirebaseAI?
  146. try autoreleasepool {
  147. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  148. gcmSenderID: "00000000000000000-00000000000-000000000")
  149. options.projectID = VertexComponentTests.projectID
  150. options.apiKey = VertexComponentTests.apiKey
  151. let app1 = FirebaseApp(instanceWithName: "transitory app", options: options)
  152. weakApp = try XCTUnwrap(app1)
  153. let vertex = FirebaseAI(
  154. app: app1,
  155. location: "transitory location",
  156. apiConfig: FirebaseAI.defaultVertexAIAPIConfig
  157. )
  158. weakVertex = vertex
  159. XCTAssertNotNil(weakVertex)
  160. }
  161. XCTAssertNil(weakApp)
  162. XCTAssertNil(weakVertex)
  163. }
  164. func testModelResourceName_vertexAI() throws {
  165. let app = try XCTUnwrap(VertexComponentTests.app)
  166. let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
  167. let model = "test-model-name"
  168. let projectID = vertex.firebaseInfo.projectID
  169. let modelResourceName = vertex.modelResourceName(modelName: model)
  170. let location = try XCTUnwrap(vertex.location)
  171. XCTAssertEqual(
  172. modelResourceName,
  173. "projects/\(projectID)/locations/\(location)/publishers/google/models/\(model)"
  174. )
  175. }
  176. func testModelResourceName_developerAPI_generativeLanguage() throws {
  177. let app = try XCTUnwrap(VertexComponentTests.app)
  178. let apiConfig = APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta)
  179. let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig)
  180. let model = "test-model-name"
  181. let modelResourceName = vertex.modelResourceName(modelName: model)
  182. XCTAssertEqual(modelResourceName, "models/\(model)")
  183. }
  184. func testModelResourceName_developerAPI_firebaseVertexAI() throws {
  185. let app = try XCTUnwrap(VertexComponentTests.app)
  186. let apiConfig = APIConfig(
  187. service: .googleAI(endpoint: .firebaseProxyStaging),
  188. version: .v1beta
  189. )
  190. let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig)
  191. let model = "test-model-name"
  192. let projectID = vertex.firebaseInfo.projectID
  193. let modelResourceName = vertex.modelResourceName(modelName: model)
  194. XCTAssertEqual(modelResourceName, "projects/\(projectID)/models/\(model)")
  195. }
  196. func testGenerativeModel_vertexAI() async throws {
  197. let app = try XCTUnwrap(VertexComponentTests.app)
  198. let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
  199. let modelResourceName = vertex.modelResourceName(modelName: modelName)
  200. let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts)
  201. let generativeModel = vertex.generativeModel(
  202. modelName: modelName,
  203. systemInstruction: systemInstruction
  204. )
  205. XCTAssertEqual(generativeModel.modelResourceName, modelResourceName)
  206. XCTAssertEqual(generativeModel.systemInstruction, expectedSystemInstruction)
  207. XCTAssertEqual(generativeModel.apiConfig, FirebaseAI.defaultVertexAIAPIConfig)
  208. }
  209. func testGenerativeModel_developerAPI() async throws {
  210. let app = try XCTUnwrap(VertexComponentTests.app)
  211. let apiConfig = APIConfig(
  212. service: .googleAI(endpoint: .firebaseProxyStaging),
  213. version: .v1beta
  214. )
  215. let vertex = FirebaseAI.createInstance(app: app, location: nil, apiConfig: apiConfig)
  216. let modelResourceName = vertex.modelResourceName(modelName: modelName)
  217. let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts)
  218. let generativeModel = vertex.generativeModel(
  219. modelName: modelName,
  220. systemInstruction: systemInstruction
  221. )
  222. XCTAssertEqual(generativeModel.modelResourceName, modelResourceName)
  223. XCTAssertEqual(generativeModel.systemInstruction, expectedSystemInstruction)
  224. XCTAssertEqual(generativeModel.apiConfig, apiConfig)
  225. }
  226. }