IntegrationTests.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // Copyright 2021 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. import Foundation
  15. import FirebaseFunctions
  16. import FirebaseFunctionsTestingSupport
  17. import XCTest
  18. /// This file was intitialized as a direct port of the Objective C
  19. /// FirebaseFunctions/Tests/Integration/FIRIntegrationTests.m
  20. ///
  21. /// The tests require the emulator to be running with `FirebaseFunctions/Backend/start.sh synchronous`
  22. /// The Firebase Functions called in the tests are implemented in `FirebaseFunctions/Backend/index.js`.
  23. class IntegrationTests: XCTestCase {
  24. let functions = FunctionsFake(
  25. projectID: "functions-integration-test",
  26. region: "us-central1",
  27. customDomain: nil,
  28. withToken: nil
  29. )
  30. let projectID = "functions-swift-integration-test"
  31. override func setUp() {
  32. super.setUp()
  33. functions.useLocalhost()
  34. }
  35. func testData() {
  36. let expectation = expectation(description: #function)
  37. let data = [
  38. "bool": true,
  39. "int": 2 as Int32,
  40. "long": 9_876_543_210,
  41. "string": "four",
  42. "array": [5 as Int32, 6 as Int32],
  43. "null": nil,
  44. ] as [String: Any?]
  45. let function = functions.httpsCallable("dataTest")
  46. XCTAssertNotNil(function)
  47. function.call(data) { result, error in
  48. do {
  49. XCTAssertNil(error)
  50. let data = try XCTUnwrap(result?.data as? [String: Any])
  51. let message = try XCTUnwrap(data["message"] as? String)
  52. let long = try XCTUnwrap(data["long"] as? Int64)
  53. let code = try XCTUnwrap(data["code"] as? Int32)
  54. XCTAssertEqual(message, "stub response")
  55. XCTAssertEqual(long, 420)
  56. XCTAssertEqual(code, 42)
  57. expectation.fulfill()
  58. } catch {
  59. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  60. }
  61. }
  62. waitForExpectations(timeout: 5)
  63. }
  64. #if compiler(>=5.5) && canImport(_Concurrency)
  65. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  66. func testDataAsync() async throws {
  67. let input = [
  68. "bool": true,
  69. "int": 2 as Int32,
  70. "long": 9_876_543_210,
  71. "string": "four",
  72. "array": [5 as Int32, 6 as Int32],
  73. "null": nil,
  74. ] as [String: Any?]
  75. let function = functions.httpsCallable("dataTest")
  76. XCTAssertNotNil(function)
  77. let result = try await function.call(input)
  78. let data = try XCTUnwrap(result.data as? [String: Any])
  79. let message = try XCTUnwrap(data["message"] as? String)
  80. let long = try XCTUnwrap(data["long"] as? Int64)
  81. let code = try XCTUnwrap(data["code"] as? Int32)
  82. XCTAssertEqual(message, "stub response")
  83. XCTAssertEqual(long, 420)
  84. XCTAssertEqual(code, 42)
  85. }
  86. #endif
  87. func testScalar() {
  88. let expectation = expectation(description: #function)
  89. let function = functions.httpsCallable("scalarTest")
  90. XCTAssertNotNil(function)
  91. function.call(17 as Int16) { result, error in
  92. do {
  93. XCTAssertNil(error)
  94. let data = try XCTUnwrap(result?.data as? Int)
  95. XCTAssertEqual(data, 76)
  96. expectation.fulfill()
  97. } catch {
  98. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  99. }
  100. }
  101. waitForExpectations(timeout: 5)
  102. }
  103. #if compiler(>=5.5) && canImport(_Concurrency)
  104. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  105. func testScalarAsync() async throws {
  106. let function = functions.httpsCallable("scalarTest")
  107. XCTAssertNotNil(function)
  108. let result = try await function.call(17 as Int16)
  109. let data = try XCTUnwrap(result.data as? Int)
  110. XCTAssertEqual(data, 76)
  111. }
  112. #endif
  113. func testToken() {
  114. // Recreate functions with a token.
  115. let functions = FunctionsFake(
  116. projectID: "functions-integration-test",
  117. region: "us-central1",
  118. customDomain: nil,
  119. withToken: "token"
  120. )
  121. functions.useLocalhost()
  122. let expectation = expectation(description: #function)
  123. let function = functions.httpsCallable("FCMTokenTest")
  124. XCTAssertNotNil(function)
  125. function.call([:]) { result, error in
  126. do {
  127. XCTAssertNil(error)
  128. let data = try XCTUnwrap(result?.data) as? [String: Int]
  129. XCTAssertEqual(data, [:])
  130. expectation.fulfill()
  131. } catch {
  132. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  133. }
  134. }
  135. waitForExpectations(timeout: 5)
  136. }
  137. #if compiler(>=5.5) && canImport(_Concurrency)
  138. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  139. func testTokenAsync() async throws {
  140. // Recreate functions with a token.
  141. let functions = FunctionsFake(
  142. projectID: "functions-integration-test",
  143. region: "us-central1",
  144. customDomain: nil,
  145. withToken: "token"
  146. )
  147. functions.useLocalhost()
  148. let function = functions.httpsCallable("FCMTokenTest")
  149. XCTAssertNotNil(function)
  150. let result = try await function.call([:])
  151. let data = try XCTUnwrap(result.data) as? [String: Int]
  152. XCTAssertEqual(data, [:])
  153. }
  154. #endif
  155. func testFCMToken() {
  156. let expectation = expectation(description: #function)
  157. let function = functions.httpsCallable("FCMTokenTest")
  158. XCTAssertNotNil(function)
  159. function.call([:]) { result, error in
  160. do {
  161. XCTAssertNil(error)
  162. let data = try XCTUnwrap(result?.data) as? [String: Int]
  163. XCTAssertEqual(data, [:])
  164. expectation.fulfill()
  165. } catch {
  166. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  167. }
  168. }
  169. waitForExpectations(timeout: 5)
  170. }
  171. #if compiler(>=5.5) && canImport(_Concurrency)
  172. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  173. func testFCMTokenAsync() async throws {
  174. let function = functions.httpsCallable("FCMTokenTest")
  175. XCTAssertNotNil(function)
  176. let result = try await function.call([:])
  177. let data = try XCTUnwrap(result.data) as? [String: Int]
  178. XCTAssertEqual(data, [:])
  179. }
  180. #endif
  181. func testNull() {
  182. let expectation = expectation(description: #function)
  183. let function = functions.httpsCallable("nullTest")
  184. XCTAssertNotNil(function)
  185. function.call(nil) { result, error in
  186. do {
  187. XCTAssertNil(error)
  188. let data = try XCTUnwrap(result?.data) as? NSNull
  189. XCTAssertEqual(data, NSNull())
  190. expectation.fulfill()
  191. } catch {
  192. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  193. }
  194. }
  195. waitForExpectations(timeout: 5)
  196. }
  197. #if compiler(>=5.5) && canImport(_Concurrency)
  198. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  199. func testNullAsync() async throws {
  200. let function = functions.httpsCallable("nullTest")
  201. XCTAssertNotNil(function)
  202. let result = try await function.call(nil)
  203. let data = try XCTUnwrap(result.data) as? NSNull
  204. XCTAssertEqual(data, NSNull())
  205. }
  206. #endif
  207. // No parameters to call should be the same as passing nil.
  208. func testParameterless() {
  209. let expectation = expectation(description: #function)
  210. let function = functions.httpsCallable("nullTest")
  211. XCTAssertNotNil(function)
  212. function.call { result, error in
  213. do {
  214. XCTAssertNil(error)
  215. let data = try XCTUnwrap(result?.data) as? NSNull
  216. XCTAssertEqual(data, NSNull())
  217. expectation.fulfill()
  218. } catch {
  219. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  220. }
  221. }
  222. waitForExpectations(timeout: 5)
  223. }
  224. #if compiler(>=5.5) && canImport(_Concurrency)
  225. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  226. func testParameterlessAsync() async throws {
  227. let function = functions.httpsCallable("nullTest")
  228. XCTAssertNotNil(function)
  229. let result = try await function.call()
  230. let data = try XCTUnwrap(result.data) as? NSNull
  231. XCTAssertEqual(data, NSNull())
  232. }
  233. #endif
  234. func testMissingResult() {
  235. let expectation = expectation(description: #function)
  236. let function = functions.httpsCallable("missingResultTest")
  237. XCTAssertNotNil(function)
  238. function.call(nil) { result, error in
  239. do {
  240. XCTAssertNotNil(error)
  241. let error = try XCTUnwrap(error) as NSError
  242. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  243. XCTAssertEqual("Response is missing data field.", error.localizedDescription)
  244. expectation.fulfill()
  245. } catch {
  246. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  247. }
  248. }
  249. XCTAssert(true)
  250. waitForExpectations(timeout: 5)
  251. }
  252. #if compiler(>=5.5) && canImport(_Concurrency)
  253. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  254. func testMissingResultAsync() async throws {
  255. let function = functions.httpsCallable("missingResultTest")
  256. XCTAssertNotNil(function)
  257. do {
  258. _ = try await function.call(nil)
  259. } catch {
  260. let error = try XCTUnwrap(error) as NSError
  261. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  262. XCTAssertEqual("Response is missing data field.", error.localizedDescription)
  263. return
  264. }
  265. XCTAssertFalse(true, "Failed to throw error for missing result")
  266. }
  267. #endif
  268. func testUnhandledError() {
  269. let expectation = expectation(description: #function)
  270. let function = functions.httpsCallable("unhandledErrorTest")
  271. XCTAssertNotNil(function)
  272. function.call([]) { result, error in
  273. do {
  274. XCTAssertNotNil(error)
  275. let error = try XCTUnwrap(error! as NSError)
  276. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  277. XCTAssertEqual("INTERNAL", error.localizedDescription)
  278. expectation.fulfill()
  279. } catch {
  280. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  281. }
  282. }
  283. XCTAssert(true)
  284. waitForExpectations(timeout: 5)
  285. }
  286. #if compiler(>=5.5) && canImport(_Concurrency)
  287. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  288. func testUnhandledErrorAsync() async throws {
  289. let function = functions.httpsCallable("unhandledErrorTest")
  290. XCTAssertNotNil(function)
  291. do {
  292. _ = try await function.call([])
  293. } catch {
  294. let error = try XCTUnwrap(error) as NSError
  295. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  296. XCTAssertEqual("INTERNAL", error.localizedDescription)
  297. return
  298. }
  299. XCTAssertFalse(true, "Failed to throw error for missing result")
  300. }
  301. #endif
  302. func testUnknownError() {
  303. let expectation = expectation(description: #function)
  304. let function = functions.httpsCallable("unknownErrorTest")
  305. XCTAssertNotNil(function)
  306. function.call([]) { result, error in
  307. do {
  308. XCTAssertNotNil(error)
  309. let error = try XCTUnwrap(error! as NSError)
  310. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  311. XCTAssertEqual("INTERNAL", error.localizedDescription)
  312. expectation.fulfill()
  313. } catch {
  314. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  315. }
  316. }
  317. XCTAssert(true)
  318. waitForExpectations(timeout: 5)
  319. }
  320. #if compiler(>=5.5) && canImport(_Concurrency)
  321. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  322. func testUnknownErrorAsync() async throws {
  323. let function = functions.httpsCallable("unknownErrorTest")
  324. XCTAssertNotNil(function)
  325. do {
  326. _ = try await function.call([])
  327. } catch {
  328. let error = try XCTUnwrap(error) as NSError
  329. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  330. XCTAssertEqual("INTERNAL", error.localizedDescription)
  331. return
  332. }
  333. XCTAssertFalse(true, "Failed to throw error for missing result")
  334. }
  335. #endif
  336. func testExplicitError() {
  337. let expectation = expectation(description: #function)
  338. let function = functions.httpsCallable("explicitErrorTest")
  339. XCTAssertNotNil(function)
  340. function.call([]) { result, error in
  341. do {
  342. XCTAssertNotNil(error)
  343. let error = try XCTUnwrap(error! as NSError)
  344. XCTAssertEqual(FunctionsErrorCode.outOfRange.rawValue, error.code)
  345. XCTAssertEqual("explicit nope", error.localizedDescription)
  346. XCTAssertEqual(["start": 10 as Int32, "end": 20 as Int32, "long": 30],
  347. error.userInfo[FunctionsErrorDetailsKey] as! [String: Int32])
  348. expectation.fulfill()
  349. } catch {
  350. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  351. }
  352. }
  353. XCTAssert(true)
  354. waitForExpectations(timeout: 5)
  355. }
  356. #if compiler(>=5.5) && canImport(_Concurrency)
  357. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  358. func testExplicitErrorAsync() async throws {
  359. let function = functions.httpsCallable("explicitErrorTest")
  360. XCTAssertNotNil(function)
  361. do {
  362. _ = try await function.call([])
  363. } catch {
  364. let error = try XCTUnwrap(error) as NSError
  365. XCTAssertEqual(FunctionsErrorCode.outOfRange.rawValue, error.code)
  366. XCTAssertEqual("explicit nope", error.localizedDescription)
  367. XCTAssertEqual(["start": 10 as Int32, "end": 20 as Int32, "long": 30],
  368. error.userInfo[FunctionsErrorDetailsKey] as! [String: Int32])
  369. return
  370. }
  371. XCTAssertFalse(true, "Failed to throw error for missing result")
  372. }
  373. #endif
  374. func testHttpError() {
  375. let expectation = expectation(description: #function)
  376. let function = functions.httpsCallable("httpErrorTest")
  377. XCTAssertNotNil(function)
  378. function.call([]) { result, error in
  379. do {
  380. XCTAssertNotNil(error)
  381. let error = try XCTUnwrap(error! as NSError)
  382. XCTAssertEqual(FunctionsErrorCode.invalidArgument.rawValue, error.code)
  383. expectation.fulfill()
  384. } catch {
  385. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  386. }
  387. }
  388. XCTAssert(true)
  389. waitForExpectations(timeout: 5)
  390. }
  391. #if compiler(>=5.5) && canImport(_Concurrency)
  392. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  393. func testHttpErrorAsync() async throws {
  394. let function = functions.httpsCallable("httpErrorTest")
  395. XCTAssertNotNil(function)
  396. do {
  397. _ = try await function.call([])
  398. } catch {
  399. let error = try XCTUnwrap(error) as NSError
  400. XCTAssertEqual(FunctionsErrorCode.invalidArgument.rawValue, error.code)
  401. return
  402. }
  403. XCTAssertFalse(true, "Failed to throw error for missing result")
  404. }
  405. #endif
  406. func testTimeout() {
  407. let expectation = expectation(description: #function)
  408. let function = functions.httpsCallable("timeoutTest")
  409. XCTAssertNotNil(function)
  410. function.timeoutInterval = 0.05
  411. function.call([]) { result, error in
  412. do {
  413. XCTAssertNotNil(error)
  414. let error = try XCTUnwrap(error! as NSError)
  415. XCTAssertEqual(FunctionsErrorCode.deadlineExceeded.rawValue, error.code)
  416. XCTAssertEqual("DEADLINE EXCEEDED", error.localizedDescription)
  417. XCTAssertNil(error.userInfo[FunctionsErrorDetailsKey])
  418. expectation.fulfill()
  419. } catch {
  420. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  421. }
  422. }
  423. XCTAssert(true)
  424. waitForExpectations(timeout: 5)
  425. }
  426. #if compiler(>=5.5) && canImport(_Concurrency)
  427. @available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
  428. func testTimeoutAsync() async throws {
  429. let function = functions.httpsCallable("timeoutTest")
  430. XCTAssertNotNil(function)
  431. function.timeoutInterval = 0.05
  432. do {
  433. _ = try await function.call([])
  434. } catch {
  435. let error = try XCTUnwrap(error) as NSError
  436. XCTAssertEqual(FunctionsErrorCode.deadlineExceeded.rawValue, error.code)
  437. XCTAssertEqual("DEADLINE EXCEEDED", error.localizedDescription)
  438. XCTAssertNil(error.userInfo[FunctionsErrorDetailsKey])
  439. return
  440. }
  441. XCTAssertFalse(true, "Failed to throw error for missing result")
  442. }
  443. #endif
  444. }