VertexComponentTests.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. useLimitedUseAppCheckTokens: false
  134. )
  135. let vertex2 = FirebaseAI.createInstance(
  136. app: VertexComponentTests.app,
  137. location: location,
  138. apiConfig: APIConfig(service: .vertexAI(endpoint: .firebaseProxyProd), version: .v1),
  139. useLimitedUseAppCheckTokens: false
  140. )
  141. // Ensure they are different instances.
  142. XCTAssert(vertex1 !== vertex2)
  143. }
  144. /// Test that vertex instances get deallocated.
  145. func testVertexLifecycle() throws {
  146. weak var weakApp: FirebaseApp?
  147. weak var weakVertex: FirebaseAI?
  148. try autoreleasepool {
  149. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  150. gcmSenderID: "00000000000000000-00000000000-000000000")
  151. options.projectID = VertexComponentTests.projectID
  152. options.apiKey = VertexComponentTests.apiKey
  153. let app1 = FirebaseApp(instanceWithName: "transitory app", options: options)
  154. weakApp = try XCTUnwrap(app1)
  155. let vertex = FirebaseAI(
  156. app: app1,
  157. location: "transitory location",
  158. apiConfig: FirebaseAI.defaultVertexAIAPIConfig,
  159. useLimitedUseAppCheckTokens: false
  160. )
  161. weakVertex = vertex
  162. XCTAssertNotNil(weakVertex)
  163. }
  164. XCTAssertNil(weakApp)
  165. XCTAssertNil(weakVertex)
  166. }
  167. func testModelResourceName_vertexAI() throws {
  168. let app = try XCTUnwrap(VertexComponentTests.app)
  169. let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
  170. let model = "test-model-name"
  171. let projectID = vertex.firebaseInfo.projectID
  172. let modelResourceName = vertex.modelResourceName(modelName: model)
  173. let location = try XCTUnwrap(vertex.location)
  174. XCTAssertEqual(
  175. modelResourceName,
  176. "projects/\(projectID)/locations/\(location)/publishers/google/models/\(model)"
  177. )
  178. }
  179. func testModelResourceName_developerAPI_generativeLanguage() throws {
  180. let app = try XCTUnwrap(VertexComponentTests.app)
  181. let apiConfig = APIConfig(service: .googleAI(endpoint: .googleAIBypassProxy), version: .v1beta)
  182. let vertex = FirebaseAI.createInstance(
  183. app: app,
  184. location: nil,
  185. apiConfig: apiConfig,
  186. useLimitedUseAppCheckTokens: false
  187. )
  188. let model = "test-model-name"
  189. let modelResourceName = vertex.modelResourceName(modelName: model)
  190. XCTAssertEqual(modelResourceName, "models/\(model)")
  191. }
  192. func testModelResourceName_developerAPI_firebaseVertexAI() throws {
  193. let app = try XCTUnwrap(VertexComponentTests.app)
  194. let apiConfig = APIConfig(
  195. service: .googleAI(endpoint: .firebaseProxyStaging),
  196. version: .v1beta
  197. )
  198. let vertex = FirebaseAI.createInstance(
  199. app: app,
  200. location: nil,
  201. apiConfig: apiConfig,
  202. useLimitedUseAppCheckTokens: false
  203. )
  204. let model = "test-model-name"
  205. let projectID = vertex.firebaseInfo.projectID
  206. let modelResourceName = vertex.modelResourceName(modelName: model)
  207. XCTAssertEqual(modelResourceName, "projects/\(projectID)/models/\(model)")
  208. }
  209. func testGenerativeModel_vertexAI() async throws {
  210. let app = try XCTUnwrap(VertexComponentTests.app)
  211. let vertex = FirebaseAI.firebaseAI(app: app, backend: .vertexAI(location: location))
  212. let modelResourceName = vertex.modelResourceName(modelName: modelName)
  213. let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts)
  214. let generativeModel = vertex.generativeModel(
  215. modelName: modelName,
  216. systemInstruction: systemInstruction
  217. )
  218. XCTAssertEqual(generativeModel.modelResourceName, modelResourceName)
  219. XCTAssertEqual(generativeModel.systemInstruction, expectedSystemInstruction)
  220. XCTAssertEqual(generativeModel.apiConfig, FirebaseAI.defaultVertexAIAPIConfig)
  221. }
  222. func testGenerativeModel_developerAPI() async throws {
  223. let app = try XCTUnwrap(VertexComponentTests.app)
  224. let apiConfig = APIConfig(
  225. service: .googleAI(endpoint: .firebaseProxyStaging),
  226. version: .v1beta
  227. )
  228. let vertex = FirebaseAI.createInstance(
  229. app: app,
  230. location: nil,
  231. apiConfig: apiConfig,
  232. useLimitedUseAppCheckTokens: false
  233. )
  234. let modelResourceName = vertex.modelResourceName(modelName: modelName)
  235. let expectedSystemInstruction = ModelContent(role: nil, parts: systemInstruction.parts)
  236. let generativeModel = vertex.generativeModel(
  237. modelName: modelName,
  238. systemInstruction: systemInstruction
  239. )
  240. XCTAssertEqual(generativeModel.modelResourceName, modelResourceName)
  241. XCTAssertEqual(generativeModel.systemInstruction, expectedSystemInstruction)
  242. XCTAssertEqual(generativeModel.apiConfig, apiConfig)
  243. }
  244. }