HTTPSCallableTests.swift 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 Combine
  16. import FirebaseCore
  17. import FirebaseFunctionsCombineSwift
  18. @testable import FirebaseFunctionsTestingSupport
  19. import XCTest
  20. // hardcoded in FIRHTTPSCallable.m
  21. private let kFunctionsTimeout: TimeInterval = 70.0
  22. private let expectationTimeout: TimeInterval = 2
  23. class MockFunctions: Functions {
  24. var mockCallFunction: () throws -> HTTPSCallableResult?
  25. var verifyParameters: ((_ name: String, _ data: Any?, _ timeout: TimeInterval) throws -> Void)?
  26. override func callFunction(_ name: String,
  27. with data: Any?,
  28. timeout: TimeInterval,
  29. completion: @escaping (HTTPSCallableResult?, Error?) -> Void) {
  30. do {
  31. try verifyParameters?(name, data, timeout)
  32. let result = try mockCallFunction()
  33. completion(result, nil)
  34. } catch {
  35. completion(nil, error)
  36. }
  37. }
  38. }
  39. @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)
  40. class HTTPSCallableTests: XCTestCase {
  41. override func setUp() {
  42. super.setUp()
  43. if FirebaseApp.app() == nil {
  44. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  45. gcmSenderID: "00000000000000000-00000000000-000000000")
  46. FirebaseApp.configure(options: options)
  47. }
  48. }
  49. func testCallWithoutParametersSuccess() {
  50. // given
  51. var cancellables = Set<AnyCancellable>()
  52. let httpsFunctionWasCalledExpectation = expectation(description: "HTTPS Function was called")
  53. let functionWasCalledExpectation = expectation(description: "Function was called")
  54. let functions = MockFunctions.functions()
  55. let expectedResult = "mockResult w/o parameters"
  56. functions.mockCallFunction = {
  57. httpsFunctionWasCalledExpectation.fulfill()
  58. return HTTPSCallableResultFake(data: expectedResult)
  59. }
  60. let dummyFunction = functions.httpsCallable("dummyFunction")
  61. // when
  62. dummyFunction.call()
  63. .sink { completion in
  64. switch completion {
  65. case .finished:
  66. print("Finished")
  67. case let .failure(error):
  68. XCTFail("💥 Something went wrong: \(error)")
  69. }
  70. } receiveValue: { functionResult in
  71. guard let result = functionResult.data as? String else {
  72. XCTFail("Expected String data")
  73. return
  74. }
  75. XCTAssertEqual(result, expectedResult)
  76. functionWasCalledExpectation.fulfill()
  77. }
  78. .store(in: &cancellables)
  79. // then
  80. wait(
  81. for: [functionWasCalledExpectation, httpsFunctionWasCalledExpectation],
  82. timeout: expectationTimeout
  83. )
  84. }
  85. func testCallWithParametersSuccess() {
  86. // given
  87. var cancellables = Set<AnyCancellable>()
  88. let httpsFunctionWasCalledExpectation = expectation(description: "HTTPS Function was called")
  89. let functionWasCalledExpectation = expectation(description: "Function was called")
  90. let functions = MockFunctions.functions()
  91. let inputParameter = "input parameter"
  92. let expectedResult = "mockResult w/ parameters: \(inputParameter)"
  93. functions.verifyParameters = { name, data, timeout in
  94. XCTAssertEqual(name as String, "dummyFunction")
  95. XCTAssertEqual(data as? String, inputParameter)
  96. XCTAssertEqual(timeout as TimeInterval, kFunctionsTimeout)
  97. }
  98. functions.mockCallFunction = {
  99. httpsFunctionWasCalledExpectation.fulfill()
  100. return HTTPSCallableResultFake(data: expectedResult)
  101. }
  102. let dummyFunction = functions.httpsCallable("dummyFunction")
  103. // when
  104. dummyFunction.call(inputParameter)
  105. .sink { completion in
  106. switch completion {
  107. case .finished:
  108. print("Finished")
  109. case let .failure(error):
  110. XCTFail("💥 Something went wrong: \(error)")
  111. }
  112. } receiveValue: { functionResult in
  113. guard let result = functionResult.data as? String else {
  114. XCTFail("Expected String data")
  115. return
  116. }
  117. XCTAssertEqual(result, expectedResult)
  118. functionWasCalledExpectation.fulfill()
  119. }
  120. .store(in: &cancellables)
  121. // then
  122. wait(
  123. for: [httpsFunctionWasCalledExpectation, functionWasCalledExpectation],
  124. timeout: expectationTimeout
  125. )
  126. }
  127. func testCallWithParametersFailure() {
  128. // given
  129. var cancellables = Set<AnyCancellable>()
  130. let httpsFunctionWasCalledExpectation = expectation(description: "HTTPS Function was called")
  131. let functionCallFailedExpectation = expectation(description: "Function call failed")
  132. let functions = MockFunctions.functions()
  133. let inputParameter = "input parameter"
  134. functions.verifyParameters = { name, data, timeout in
  135. XCTAssertEqual(name as String, "dummyFunction")
  136. XCTAssertEqual(data as? String, inputParameter)
  137. XCTAssertEqual(timeout as TimeInterval, kFunctionsTimeout)
  138. }
  139. functions.mockCallFunction = {
  140. httpsFunctionWasCalledExpectation.fulfill()
  141. throw NSError(domain: FunctionsErrorDomain,
  142. code: FunctionsErrorCode.internal.rawValue,
  143. userInfo: [NSLocalizedDescriptionKey: "Response is missing data field."])
  144. }
  145. let dummyFunction = functions.httpsCallable("dummyFunction")
  146. // when
  147. dummyFunction.call(inputParameter)
  148. .sink { completion in
  149. if case let .failure(error as NSError) = completion {
  150. // Verify user mismatch error.
  151. XCTAssertEqual(error.code, FunctionsErrorCode.internal.rawValue)
  152. functionCallFailedExpectation.fulfill()
  153. }
  154. } receiveValue: { functionResult in
  155. XCTFail("💥 result unexpected")
  156. }
  157. .store(in: &cancellables)
  158. // then
  159. wait(
  160. for: [functionCallFailedExpectation, httpsFunctionWasCalledExpectation],
  161. timeout: expectationTimeout
  162. )
  163. }
  164. }