IntegrationTests.swift 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  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. @testable import FirebaseFunctions
  16. import FirebaseAuthInterop
  17. import FirebaseMessagingInterop
  18. import XCTest
  19. /// This file was intitialized as a direct port of `FirebaseFunctionsSwift/Tests/IntegrationTests.swift`
  20. /// which itself was ported from the Objective C `FirebaseFunctions/Tests/Integration/FIRIntegrationTests.m`
  21. ///
  22. /// The tests require the emulator to be running with `FirebaseFunctions/Backend/start.sh synchronous`
  23. /// The Firebase Functions called in the tests are implemented in `FirebaseFunctions/Backend/index.js`.
  24. struct DataTestRequest: Encodable {
  25. var bool: Bool
  26. var int: Int32
  27. var long: Int64
  28. var string: String
  29. var array: [Int32]
  30. // NOTE: Auto-synthesized Encodable conformance uses 'encodeIfPresent' to
  31. // encode Optional values. To encode Optional.none as null you either need
  32. // to write a manual encodable conformance or use a helper like the
  33. // propertyWrapper here:
  34. @NullEncodable var null: Bool?
  35. }
  36. @propertyWrapper
  37. struct NullEncodable<T>: Encodable where T: Encodable {
  38. var wrappedValue: T?
  39. init(wrappedValue: T?) {
  40. self.wrappedValue = wrappedValue
  41. }
  42. func encode(to encoder: Encoder) throws {
  43. var container = encoder.singleValueContainer()
  44. switch wrappedValue {
  45. case let .some(value): try container.encode(value)
  46. case .none: try container.encodeNil()
  47. }
  48. }
  49. }
  50. struct DataTestResponse: Decodable, Equatable {
  51. var message: String
  52. var long: Int64
  53. var code: Int32
  54. }
  55. class IntegrationTests: XCTestCase {
  56. let functions = Functions(projectID: "functions-integration-test",
  57. region: "us-central1",
  58. customDomain: nil,
  59. auth: nil,
  60. messaging: MessagingTokenProvider(),
  61. appCheck: nil)
  62. override func setUp() {
  63. super.setUp()
  64. functions.useEmulator(withHost: "localhost", port: 5005)
  65. }
  66. func emulatorURL(_ funcName: String) -> URL {
  67. return URL(string: "http://localhost:5005/functions-integration-test/us-central1/\(funcName)")!
  68. }
  69. func testData() {
  70. let data = DataTestRequest(
  71. bool: true,
  72. int: 2,
  73. long: 9_876_543_210,
  74. string: "four",
  75. array: [5, 6],
  76. null: nil
  77. )
  78. let byName = functions.httpsCallable("dataTest",
  79. requestAs: DataTestRequest.self,
  80. responseAs: DataTestResponse.self)
  81. let byURL = functions.httpsCallable(emulatorURL("dataTest"),
  82. requestAs: DataTestRequest.self,
  83. responseAs: DataTestResponse.self)
  84. for function in [byName, byURL] {
  85. let expectation = expectation(description: #function)
  86. function.call(data) { result in
  87. do {
  88. let response = try result.get()
  89. let expected = DataTestResponse(
  90. message: "stub response",
  91. long: 420,
  92. code: 42
  93. )
  94. XCTAssertEqual(response, expected)
  95. } catch {
  96. XCTFail("Failed to unwrap the function result: \(error)")
  97. }
  98. expectation.fulfill()
  99. }
  100. waitForExpectations(timeout: 5)
  101. }
  102. }
  103. #if compiler(>=5.5.2) && canImport(_Concurrency)
  104. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  105. func testDataAsync() async throws {
  106. let data = DataTestRequest(
  107. bool: true,
  108. int: 2,
  109. long: 9_876_543_210,
  110. string: "four",
  111. array: [5, 6],
  112. null: nil
  113. )
  114. let byName = functions.httpsCallable("dataTest",
  115. requestAs: DataTestRequest.self,
  116. responseAs: DataTestResponse.self)
  117. let byUrl = functions.httpsCallable(emulatorURL("dataTest"),
  118. requestAs: DataTestRequest.self,
  119. responseAs: DataTestResponse.self)
  120. for function in [byName, byUrl] {
  121. let response = try await function.call(data)
  122. let expected = DataTestResponse(
  123. message: "stub response",
  124. long: 420,
  125. code: 42
  126. )
  127. XCTAssertEqual(response, expected)
  128. }
  129. }
  130. #endif
  131. func testScalar() {
  132. let byName = functions.httpsCallable(
  133. "scalarTest",
  134. requestAs: Int16.self,
  135. responseAs: Int.self
  136. )
  137. let byURL = functions.httpsCallable(
  138. emulatorURL("scalarTest"),
  139. requestAs: Int16.self,
  140. responseAs: Int.self
  141. )
  142. for function in [byName, byURL] {
  143. let expectation = expectation(description: #function)
  144. function.call(17) { result in
  145. do {
  146. let response = try result.get()
  147. XCTAssertEqual(response, 76)
  148. } catch {
  149. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  150. }
  151. expectation.fulfill()
  152. }
  153. waitForExpectations(timeout: 5)
  154. }
  155. }
  156. #if compiler(>=5.5.2) && canImport(_Concurrency)
  157. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  158. func testScalarAsync() async throws {
  159. let byName = functions.httpsCallable(
  160. "scalarTest",
  161. requestAs: Int16.self,
  162. responseAs: Int.self
  163. )
  164. let byURL = functions.httpsCallable(
  165. emulatorURL("scalarTest"),
  166. requestAs: Int16.self,
  167. responseAs: Int.self
  168. )
  169. for function in [byName, byURL] {
  170. let result = try await function.call(17)
  171. XCTAssertEqual(result, 76)
  172. }
  173. }
  174. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  175. func testScalarAsyncAlternateSignature() async throws {
  176. let byName: Callable<Int16, Int> = functions.httpsCallable("scalarTest")
  177. let byURL: Callable<Int16, Int> = functions.httpsCallable(emulatorURL("scalarTest"))
  178. for function in [byName, byURL] {
  179. let result = try await function.call(17)
  180. XCTAssertEqual(result, 76)
  181. }
  182. }
  183. #endif
  184. func testToken() {
  185. // Recreate functions with a token.
  186. let functions = Functions(
  187. projectID: "functions-integration-test",
  188. region: "us-central1",
  189. customDomain: nil,
  190. auth: AuthTokenProvider(token: "token"),
  191. messaging: MessagingTokenProvider(),
  192. appCheck: nil
  193. )
  194. functions.useEmulator(withHost: "localhost", port: 5005)
  195. let byName = functions.httpsCallable(
  196. "tokenTest",
  197. requestAs: [String: Int].self,
  198. responseAs: [String: Int].self
  199. )
  200. let byURL = functions.httpsCallable(
  201. emulatorURL("tokenTest"),
  202. requestAs: [String: Int].self,
  203. responseAs: [String: Int].self
  204. )
  205. for function in [byName, byURL] {
  206. let expectation = expectation(description: #function)
  207. XCTAssertNotNil(function)
  208. function.call([:]) { result in
  209. do {
  210. let data = try result.get()
  211. XCTAssertEqual(data, [:])
  212. } catch {
  213. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  214. }
  215. expectation.fulfill()
  216. }
  217. waitForExpectations(timeout: 5)
  218. }
  219. }
  220. #if compiler(>=5.5.2) && canImport(_Concurrency)
  221. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  222. func testTokenAsync() async throws {
  223. // Recreate functions with a token.
  224. let functions = Functions(
  225. projectID: "functions-integration-test",
  226. region: "us-central1",
  227. customDomain: nil,
  228. auth: AuthTokenProvider(token: "token"),
  229. messaging: MessagingTokenProvider(),
  230. appCheck: nil
  231. )
  232. functions.useEmulator(withHost: "localhost", port: 5005)
  233. let byName = functions.httpsCallable(
  234. "tokenTest",
  235. requestAs: [String: Int].self,
  236. responseAs: [String: Int].self
  237. )
  238. let byURL = functions.httpsCallable(
  239. emulatorURL("tokenTest"),
  240. requestAs: [String: Int].self,
  241. responseAs: [String: Int].self
  242. )
  243. for function in [byName, byURL] {
  244. let data = try await function.call([:])
  245. XCTAssertEqual(data, [:])
  246. }
  247. }
  248. #endif
  249. func testFCMToken() {
  250. let byName = functions.httpsCallable(
  251. "FCMTokenTest",
  252. requestAs: [String: Int].self,
  253. responseAs: [String: Int].self
  254. )
  255. let byURL = functions.httpsCallable(
  256. emulatorURL("FCMTokenTest"),
  257. requestAs: [String: Int].self,
  258. responseAs: [String: Int].self
  259. )
  260. for function in [byName, byURL] {
  261. let expectation = expectation(description: #function)
  262. function.call([:]) { result in
  263. do {
  264. let data = try result.get()
  265. XCTAssertEqual(data, [:])
  266. } catch {
  267. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  268. }
  269. expectation.fulfill()
  270. }
  271. waitForExpectations(timeout: 5)
  272. }
  273. }
  274. #if compiler(>=5.5.2) && canImport(_Concurrency)
  275. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  276. func testFCMTokenAsync() async throws {
  277. let byName = functions.httpsCallable(
  278. "FCMTokenTest",
  279. requestAs: [String: Int].self,
  280. responseAs: [String: Int].self
  281. )
  282. let byURL = functions.httpsCallable(
  283. emulatorURL("FCMTokenTest"),
  284. requestAs: [String: Int].self,
  285. responseAs: [String: Int].self
  286. )
  287. for function in [byName, byURL] {
  288. let data = try await function.call([:])
  289. XCTAssertEqual(data, [:])
  290. }
  291. }
  292. #endif
  293. func testNull() {
  294. let byName = functions.httpsCallable(
  295. "nullTest",
  296. requestAs: Int?.self,
  297. responseAs: Int?.self
  298. )
  299. let byURL = functions.httpsCallable(
  300. emulatorURL("nullTest"),
  301. requestAs: Int?.self,
  302. responseAs: Int?.self
  303. )
  304. for function in [byName, byURL] {
  305. let expectation = expectation(description: #function)
  306. function.call(nil) { result in
  307. do {
  308. let data = try result.get()
  309. XCTAssertEqual(data, nil)
  310. } catch {
  311. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  312. }
  313. expectation.fulfill()
  314. }
  315. waitForExpectations(timeout: 5)
  316. }
  317. }
  318. #if compiler(>=5.5.2) && canImport(_Concurrency)
  319. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  320. func testNullAsync() async throws {
  321. let byName = functions.httpsCallable(
  322. "nullTest",
  323. requestAs: Int?.self,
  324. responseAs: Int?.self
  325. )
  326. let byURL = functions.httpsCallable(
  327. emulatorURL("nullTest"),
  328. requestAs: Int?.self,
  329. responseAs: Int?.self
  330. )
  331. for function in [byName, byURL] {
  332. let data = try await function.call(nil)
  333. XCTAssertEqual(data, nil)
  334. }
  335. }
  336. #endif
  337. func testMissingResult() {
  338. let byName = functions.httpsCallable(
  339. "missingResultTest",
  340. requestAs: Int?.self,
  341. responseAs: Int?.self
  342. )
  343. let byURL = functions.httpsCallable(
  344. emulatorURL("missingResultTest"),
  345. requestAs: Int?.self,
  346. responseAs: Int?.self
  347. )
  348. for function in [byName, byURL] {
  349. let expectation = expectation(description: #function)
  350. function.call(nil) { result in
  351. do {
  352. _ = try result.get()
  353. } catch {
  354. let error = error as NSError
  355. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  356. XCTAssertEqual("Response is missing data field.", error.localizedDescription)
  357. expectation.fulfill()
  358. return
  359. }
  360. XCTFail("Failed to throw error for missing result")
  361. }
  362. waitForExpectations(timeout: 5)
  363. }
  364. }
  365. #if compiler(>=5.5.2) && canImport(_Concurrency)
  366. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  367. func testMissingResultAsync() async {
  368. let byName = functions.httpsCallable(
  369. "missingResultTest",
  370. requestAs: Int?.self,
  371. responseAs: Int?.self
  372. )
  373. let byURL = functions.httpsCallable(
  374. emulatorURL("missingResultTest"),
  375. requestAs: Int?.self,
  376. responseAs: Int?.self
  377. )
  378. for function in [byName, byURL] {
  379. do {
  380. _ = try await function.call(nil)
  381. XCTFail("Failed to throw error for missing result")
  382. } catch {
  383. let error = error as NSError
  384. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  385. XCTAssertEqual("Response is missing data field.", error.localizedDescription)
  386. }
  387. }
  388. }
  389. #endif
  390. func testUnhandledError() {
  391. let byName = functions.httpsCallable(
  392. "unhandledErrorTest",
  393. requestAs: [Int].self,
  394. responseAs: Int.self
  395. )
  396. let byURL = functions.httpsCallable(
  397. emulatorURL("unhandledErrorTest"),
  398. requestAs: [Int].self,
  399. responseAs: Int.self
  400. )
  401. for function in [byName, byURL] {
  402. let expectation = expectation(description: #function)
  403. function.call([]) { result in
  404. do {
  405. _ = try result.get()
  406. } catch {
  407. let error = error as NSError
  408. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  409. XCTAssertEqual("INTERNAL", error.localizedDescription)
  410. expectation.fulfill()
  411. return
  412. }
  413. XCTFail("Failed to throw error for missing result")
  414. }
  415. XCTAssert(true)
  416. waitForExpectations(timeout: 5)
  417. }
  418. }
  419. #if compiler(>=5.5.2) && canImport(_Concurrency)
  420. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  421. func testUnhandledErrorAsync() async {
  422. let byName = functions.httpsCallable(
  423. "unhandledErrorTest",
  424. requestAs: [Int].self,
  425. responseAs: Int.self
  426. )
  427. let byURL = functions.httpsCallable(
  428. "unhandledErrorTest",
  429. requestAs: [Int].self,
  430. responseAs: Int.self
  431. )
  432. for function in [byName, byURL] {
  433. do {
  434. _ = try await function.call([])
  435. XCTFail("Failed to throw error for missing result")
  436. } catch {
  437. let error = error as NSError
  438. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  439. XCTAssertEqual("INTERNAL", error.localizedDescription)
  440. }
  441. }
  442. }
  443. #endif
  444. func testUnknownError() {
  445. let byName = functions.httpsCallable(
  446. "unknownErrorTest",
  447. requestAs: [Int].self,
  448. responseAs: Int.self
  449. )
  450. let byURL = functions.httpsCallable(
  451. emulatorURL("unknownErrorTest"),
  452. requestAs: [Int].self,
  453. responseAs: Int.self
  454. )
  455. for function in [byName, byURL] {
  456. let expectation = expectation(description: #function)
  457. function.call([]) { result in
  458. do {
  459. _ = try result.get()
  460. } catch {
  461. let error = error as NSError
  462. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  463. XCTAssertEqual("INTERNAL", error.localizedDescription)
  464. expectation.fulfill()
  465. return
  466. }
  467. XCTFail("Failed to throw error for missing result")
  468. }
  469. }
  470. waitForExpectations(timeout: 5)
  471. }
  472. #if compiler(>=5.5.2) && canImport(_Concurrency)
  473. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  474. func testUnknownErrorAsync() async {
  475. let byName = functions.httpsCallable(
  476. "unknownErrorTest",
  477. requestAs: [Int].self,
  478. responseAs: Int.self
  479. )
  480. let byURL = functions.httpsCallable(
  481. emulatorURL("unknownErrorTest"),
  482. requestAs: [Int].self,
  483. responseAs: Int.self
  484. )
  485. for function in [byName, byURL] {
  486. do {
  487. _ = try await function.call([])
  488. XCTAssertFalse(true, "Failed to throw error for missing result")
  489. } catch {
  490. let error = error as NSError
  491. XCTAssertEqual(FunctionsErrorCode.internal.rawValue, error.code)
  492. XCTAssertEqual("INTERNAL", error.localizedDescription)
  493. }
  494. }
  495. }
  496. #endif
  497. func testExplicitError() {
  498. let byName = functions.httpsCallable(
  499. "explicitErrorTest",
  500. requestAs: [Int].self,
  501. responseAs: Int.self
  502. )
  503. let byURL = functions.httpsCallable(
  504. "explicitErrorTest",
  505. requestAs: [Int].self,
  506. responseAs: Int.self
  507. )
  508. for function in [byName, byURL] {
  509. let expectation = expectation(description: #function)
  510. function.call([]) { result in
  511. do {
  512. _ = try result.get()
  513. } catch {
  514. let error = error as NSError
  515. XCTAssertEqual(FunctionsErrorCode.outOfRange.rawValue, error.code)
  516. XCTAssertEqual("explicit nope", error.localizedDescription)
  517. XCTAssertEqual(["start": 10 as Int32, "end": 20 as Int32, "long": 30],
  518. error.userInfo["details"] as! [String: Int32])
  519. expectation.fulfill()
  520. return
  521. }
  522. XCTFail("Failed to throw error for missing result")
  523. }
  524. waitForExpectations(timeout: 5)
  525. }
  526. }
  527. #if compiler(>=5.5.2) && canImport(_Concurrency)
  528. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  529. func testExplicitErrorAsync() async {
  530. let byName = functions.httpsCallable(
  531. "explicitErrorTest",
  532. requestAs: [Int].self,
  533. responseAs: Int.self
  534. )
  535. let byURL = functions.httpsCallable(
  536. emulatorURL("explicitErrorTest"),
  537. requestAs: [Int].self,
  538. responseAs: Int.self
  539. )
  540. for function in [byName, byURL] {
  541. do {
  542. _ = try await function.call([])
  543. XCTAssertFalse(true, "Failed to throw error for missing result")
  544. } catch {
  545. let error = error as NSError
  546. XCTAssertEqual(FunctionsErrorCode.outOfRange.rawValue, error.code)
  547. XCTAssertEqual("explicit nope", error.localizedDescription)
  548. XCTAssertEqual(["start": 10 as Int32, "end": 20 as Int32, "long": 30],
  549. error.userInfo["details"] as! [String: Int32])
  550. }
  551. }
  552. }
  553. #endif
  554. func testHttpError() {
  555. let byName = functions.httpsCallable(
  556. "httpErrorTest",
  557. requestAs: [Int].self,
  558. responseAs: Int.self
  559. )
  560. let byURL = functions.httpsCallable(
  561. emulatorURL("httpErrorTest"),
  562. requestAs: [Int].self,
  563. responseAs: Int.self
  564. )
  565. for function in [byName, byURL] {
  566. let expectation = expectation(description: #function)
  567. XCTAssertNotNil(function)
  568. function.call([]) { result in
  569. do {
  570. _ = try result.get()
  571. } catch {
  572. let error = error as NSError
  573. XCTAssertEqual(FunctionsErrorCode.invalidArgument.rawValue, error.code)
  574. expectation.fulfill()
  575. return
  576. }
  577. XCTFail("Failed to throw error for missing result")
  578. }
  579. waitForExpectations(timeout: 5)
  580. }
  581. }
  582. #if compiler(>=5.5.2) && canImport(_Concurrency)
  583. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  584. func testHttpErrorAsync() async {
  585. let byName = functions.httpsCallable(
  586. "httpErrorTest",
  587. requestAs: [Int].self,
  588. responseAs: Int.self
  589. )
  590. let byURL = functions.httpsCallable(
  591. emulatorURL("httpErrorTest"),
  592. requestAs: [Int].self,
  593. responseAs: Int.self
  594. )
  595. for function in [byName, byURL] {
  596. do {
  597. _ = try await function.call([])
  598. XCTAssertFalse(true, "Failed to throw error for missing result")
  599. } catch {
  600. let error = error as NSError
  601. XCTAssertEqual(FunctionsErrorCode.invalidArgument.rawValue, error.code)
  602. }
  603. }
  604. }
  605. #endif
  606. func testTimeout() {
  607. let byName = functions.httpsCallable(
  608. "timeoutTest",
  609. requestAs: [Int].self,
  610. responseAs: Int.self
  611. )
  612. let byURL = functions.httpsCallable(
  613. emulatorURL("timeoutTest"),
  614. requestAs: [Int].self,
  615. responseAs: Int.self
  616. )
  617. for var function in [byName, byURL] {
  618. let expectation = expectation(description: #function)
  619. function.timeoutInterval = 0.05
  620. function.call([]) { result in
  621. do {
  622. _ = try result.get()
  623. } catch {
  624. let error = error as NSError
  625. XCTAssertEqual(FunctionsErrorCode.deadlineExceeded.rawValue, error.code)
  626. XCTAssertEqual("DEADLINE EXCEEDED", error.localizedDescription)
  627. XCTAssertNil(error.userInfo["details"])
  628. expectation.fulfill()
  629. return
  630. }
  631. XCTFail("Failed to throw error for missing result")
  632. }
  633. waitForExpectations(timeout: 5)
  634. }
  635. }
  636. #if compiler(>=5.5.2) && canImport(_Concurrency)
  637. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  638. func testTimeoutAsync() async {
  639. var byName = functions.httpsCallable(
  640. "timeoutTest",
  641. requestAs: [Int].self,
  642. responseAs: Int.self
  643. )
  644. byName.timeoutInterval = 0.05
  645. var byURL = functions.httpsCallable(
  646. emulatorURL("timeoutTest"),
  647. requestAs: [Int].self,
  648. responseAs: Int.self
  649. )
  650. byURL.timeoutInterval = 0.05
  651. for function in [byName, byURL] {
  652. do {
  653. _ = try await function.call([])
  654. XCTAssertFalse(true, "Failed to throw error for missing result")
  655. } catch {
  656. let error = error as NSError
  657. XCTAssertEqual(FunctionsErrorCode.deadlineExceeded.rawValue, error.code)
  658. XCTAssertEqual("DEADLINE EXCEEDED", error.localizedDescription)
  659. XCTAssertNil(error.userInfo["details"])
  660. }
  661. }
  662. }
  663. #endif
  664. func testCallAsFunction() {
  665. let data = DataTestRequest(
  666. bool: true,
  667. int: 2,
  668. long: 9_876_543_210,
  669. string: "four",
  670. array: [5, 6],
  671. null: nil
  672. )
  673. let byName = functions.httpsCallable("dataTest",
  674. requestAs: DataTestRequest.self,
  675. responseAs: DataTestResponse.self)
  676. let byURL = functions.httpsCallable(emulatorURL("dataTest"),
  677. requestAs: DataTestRequest.self,
  678. responseAs: DataTestResponse.self)
  679. for function in [byName, byURL] {
  680. let expectation = expectation(description: #function)
  681. function(data) { result in
  682. do {
  683. let response = try result.get()
  684. let expected = DataTestResponse(
  685. message: "stub response",
  686. long: 420,
  687. code: 42
  688. )
  689. XCTAssertEqual(response, expected)
  690. expectation.fulfill()
  691. } catch {
  692. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  693. }
  694. }
  695. waitForExpectations(timeout: 5)
  696. }
  697. }
  698. #if compiler(>=5.5.2) && canImport(_Concurrency)
  699. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  700. func testCallAsFunctionAsync() async throws {
  701. let data = DataTestRequest(
  702. bool: true,
  703. int: 2,
  704. long: 9_876_543_210,
  705. string: "four",
  706. array: [5, 6],
  707. null: nil
  708. )
  709. let byName = functions.httpsCallable("dataTest",
  710. requestAs: DataTestRequest.self,
  711. responseAs: DataTestResponse.self)
  712. let byURL = functions.httpsCallable(emulatorURL("dataTest"),
  713. requestAs: DataTestRequest.self,
  714. responseAs: DataTestResponse.self)
  715. for function in [byName, byURL] {
  716. let response = try await function(data)
  717. let expected = DataTestResponse(
  718. message: "stub response",
  719. long: 420,
  720. code: 42
  721. )
  722. XCTAssertEqual(response, expected)
  723. }
  724. }
  725. #endif
  726. func testInferredTypes() {
  727. let data = DataTestRequest(
  728. bool: true,
  729. int: 2,
  730. long: 9_876_543_210,
  731. string: "four",
  732. array: [5, 6],
  733. null: nil
  734. )
  735. let byName: Callable<DataTestRequest, DataTestResponse> = functions.httpsCallable("dataTest")
  736. let byURL: Callable<DataTestRequest, DataTestResponse> = functions
  737. .httpsCallable(emulatorURL("dataTest"))
  738. for function in [byName, byURL] {
  739. let expectation = expectation(description: #function)
  740. function(data) { result in
  741. do {
  742. let response = try result.get()
  743. let expected = DataTestResponse(
  744. message: "stub response",
  745. long: 420,
  746. code: 42
  747. )
  748. XCTAssertEqual(response, expected)
  749. expectation.fulfill()
  750. } catch {
  751. XCTAssert(false, "Failed to unwrap the function result: \(error)")
  752. }
  753. }
  754. waitForExpectations(timeout: 5)
  755. }
  756. }
  757. #if compiler(>=5.5.2) && canImport(_Concurrency)
  758. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  759. func testInferredTyesAsync() async throws {
  760. let data = DataTestRequest(
  761. bool: true,
  762. int: 2,
  763. long: 9_876_543_210,
  764. string: "four",
  765. array: [5, 6],
  766. null: nil
  767. )
  768. let byName: Callable<DataTestRequest, DataTestResponse> = functions
  769. .httpsCallable("dataTest")
  770. let byURL: Callable<DataTestRequest, DataTestResponse> = functions
  771. .httpsCallable(emulatorURL("dataTest"))
  772. for function in [byName, byURL] {
  773. let response = try await function(data)
  774. let expected = DataTestResponse(
  775. message: "stub response",
  776. long: 420,
  777. code: 42
  778. )
  779. XCTAssertEqual(response, expected)
  780. }
  781. }
  782. #endif
  783. }
  784. private class AuthTokenProvider: AuthInterop {
  785. func getUserID() -> String? {
  786. return "fake user"
  787. }
  788. let token: String
  789. init(token: String) {
  790. self.token = token
  791. }
  792. func getToken(forcingRefresh: Bool, completion: (String?, Error?) -> Void) {
  793. completion(token, nil)
  794. }
  795. }
  796. private class MessagingTokenProvider: NSObject, MessagingInterop {
  797. var fcmToken: String? { return "fakeFCMToken" }
  798. }