IntegrationTests.swift 26 KB

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