ContextProviderTests.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Copyright 2022 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 FirebaseCore
  16. @testable import FirebaseFunctions
  17. import FirebaseAppCheckInterop
  18. import FirebaseAuthInterop
  19. import FirebaseMessagingInterop
  20. import SharedTestUtilities
  21. import XCTest
  22. class ContextProviderTests: XCTestCase {
  23. let appCheckFake = FIRAppCheckFake()
  24. let appCheckTokenError = FIRAppCheckTokenResultFake(token: "dummy token",
  25. error: NSError(
  26. domain: "testAppCheckError",
  27. code: -1,
  28. userInfo: nil
  29. ))
  30. let appCheckTokenSuccess = FIRAppCheckTokenResultFake(token: "valid_token", error: nil)
  31. let messagingFake = FIRMessagingInteropFake()
  32. func testAsyncContextWithAuth() async throws {
  33. let auth = FIRAuthInteropFake(token: "token", userID: "userID", error: nil)
  34. let provider = FunctionsContextProvider(auth: auth, messaging: messagingFake, appCheck: nil)
  35. let context = try await provider.context(options: nil)
  36. XCTAssertNotNil(context)
  37. XCTAssertEqual(context.authToken, "token")
  38. XCTAssertEqual(context.fcmToken, messagingFake.fcmToken)
  39. }
  40. func testContextWithAuth() {
  41. let auth = FIRAuthInteropFake(token: "token", userID: "userID", error: nil)
  42. let provider = FunctionsContextProvider(auth: auth, messaging: messagingFake, appCheck: nil)
  43. let expectation = expectation(description: "Context should have auth keys.")
  44. provider.getContext { context, error in
  45. XCTAssertNotNil(context)
  46. XCTAssertEqual(context.authToken, "token")
  47. XCTAssertEqual(context.fcmToken, self.messagingFake.fcmToken)
  48. XCTAssertNil(error)
  49. expectation.fulfill()
  50. }
  51. waitForExpectations(timeout: 0.1)
  52. }
  53. func testAsyncContextWithAuthError() async {
  54. let authError = NSError(domain: "com.functions.tests", code: 4, userInfo: nil)
  55. let auth = FIRAuthInteropFake(token: nil, userID: "userID", error: authError)
  56. let provider = FunctionsContextProvider(auth: auth, messaging: messagingFake, appCheck: nil)
  57. do {
  58. _ = try await provider.context(options: nil)
  59. XCTFail("Expected an error")
  60. } catch {
  61. XCTAssertEqual(error as NSError, authError)
  62. }
  63. }
  64. func testContextWithAuthError() {
  65. let authError = NSError(domain: "com.functions.tests", code: 4, userInfo: nil)
  66. let auth = FIRAuthInteropFake(token: nil, userID: "userID", error: authError)
  67. let provider = FunctionsContextProvider(auth: auth, messaging: messagingFake, appCheck: nil)
  68. let expectation = expectation(description: "Completion handler should fail with Auth error.")
  69. provider.getContext { context, error in
  70. XCTAssertNotNil(context)
  71. XCTAssertNil(context.authToken)
  72. XCTAssertEqual(error as NSError?, authError)
  73. expectation.fulfill()
  74. }
  75. waitForExpectations(timeout: 0.1)
  76. }
  77. func testAsyncContextWithoutAuth() async throws {
  78. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: nil)
  79. let context = try await provider.context(options: nil)
  80. XCTAssertNil(context.authToken)
  81. XCTAssertNil(context.fcmToken)
  82. }
  83. func testContextWithoutAuth() {
  84. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: nil)
  85. let expectation = expectation(description: "Completion handler should succeed without Auth.")
  86. provider.getContext { context, error in
  87. XCTAssertNotNil(context)
  88. XCTAssertNil(error)
  89. XCTAssertNil(context.authToken)
  90. XCTAssertNil(context.fcmToken)
  91. expectation.fulfill()
  92. }
  93. waitForExpectations(timeout: 0.1)
  94. }
  95. func testAsyncContextWithAppCheckOnlySuccess() async throws {
  96. appCheckFake.tokenResult = appCheckTokenSuccess
  97. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: appCheckFake)
  98. let context = try await provider.context(options: nil)
  99. XCTAssertNil(context.authToken)
  100. XCTAssertNil(context.fcmToken)
  101. XCTAssertEqual(context.appCheckToken, appCheckTokenSuccess.token)
  102. }
  103. func testContextWithAppCheckOnlySuccess() {
  104. appCheckFake.tokenResult = appCheckTokenSuccess
  105. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: appCheckFake)
  106. let expectation = expectation(description: "Verify app check.")
  107. provider.getContext { context, error in
  108. XCTAssertNotNil(context)
  109. XCTAssertNil(error)
  110. XCTAssertNil(context.authToken)
  111. XCTAssertNil(context.fcmToken)
  112. XCTAssertEqual(context.appCheckToken, self.appCheckTokenSuccess.token)
  113. expectation.fulfill()
  114. }
  115. waitForExpectations(timeout: 0.1)
  116. }
  117. func testAsyncContextWithAppCheckOnlyError() async throws {
  118. appCheckFake.tokenResult = appCheckTokenError
  119. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: appCheckFake)
  120. let context = try await provider.context(options: nil)
  121. XCTAssertNil(context.authToken)
  122. XCTAssertNil(context.fcmToken)
  123. // Don't expect any token in the case of App Check error.
  124. XCTAssertNil(context.appCheckToken)
  125. }
  126. func testContextWithAppCheckOnlyError() {
  127. appCheckFake.tokenResult = appCheckTokenError
  128. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: appCheckFake)
  129. let expectation = expectation(description: "Verify bad app check token")
  130. provider.getContext { context, error in
  131. XCTAssertNotNil(context)
  132. XCTAssertNil(error)
  133. XCTAssertNil(context.authToken)
  134. XCTAssertNil(context.fcmToken)
  135. // Don't expect any token in the case of App Check error.
  136. XCTAssertNil(context.appCheckToken)
  137. expectation.fulfill()
  138. }
  139. waitForExpectations(timeout: 0.1)
  140. }
  141. func testAsyncContextWithAppCheckWithoutOptionalMethods() async throws {
  142. let appCheck = AppCheckFakeWithoutOptionalMethods(tokenResult: appCheckTokenSuccess)
  143. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: appCheck)
  144. let context = try await provider.context(options: .init(requireLimitedUseAppCheckTokens: true))
  145. XCTAssertNil(context.authToken)
  146. XCTAssertNil(context.fcmToken)
  147. XCTAssertNil(context.appCheckToken)
  148. // If the method for limited-use tokens is not implemented, the value should be `nil`:
  149. XCTAssertNil(context.limitedUseAppCheckToken)
  150. }
  151. func testContextWithAppCheckWithoutOptionalMethods() {
  152. let appCheck = AppCheckFakeWithoutOptionalMethods(tokenResult: appCheckTokenSuccess)
  153. let provider = FunctionsContextProvider(auth: nil, messaging: nil, appCheck: appCheck)
  154. let expectation =
  155. expectation(description: "Verify non-implemented method for limited-use tokens")
  156. provider.getContext(options: .init(requireLimitedUseAppCheckTokens: true)) { context, error in
  157. XCTAssertNotNil(context)
  158. XCTAssertNil(error)
  159. XCTAssertNil(context.authToken)
  160. XCTAssertNil(context.fcmToken)
  161. XCTAssertNil(context.appCheckToken)
  162. // If the method for limited-use tokens is not implemented, the value should be `nil`:
  163. XCTAssertNil(context.limitedUseAppCheckToken)
  164. expectation.fulfill()
  165. }
  166. // Importantly, `getContext(options:_:)` must still finish in a timely manner:
  167. waitForExpectations(timeout: 0.1)
  168. }
  169. func testAsyncAllContextsAvailableSuccess() async throws {
  170. appCheckFake.tokenResult = appCheckTokenSuccess
  171. let auth = FIRAuthInteropFake(token: "token", userID: "userID", error: nil)
  172. let provider = FunctionsContextProvider(
  173. auth: auth,
  174. messaging: messagingFake,
  175. appCheck: appCheckFake
  176. )
  177. let context = try await provider.context(options: nil)
  178. XCTAssertEqual(context.authToken, "token")
  179. XCTAssertEqual(context.fcmToken, messagingFake.fcmToken)
  180. XCTAssertEqual(context.appCheckToken, appCheckTokenSuccess.token)
  181. }
  182. func testAllContextsAvailableSuccess() {
  183. appCheckFake.tokenResult = appCheckTokenSuccess
  184. let auth = FIRAuthInteropFake(token: "token", userID: "userID", error: nil)
  185. let provider = FunctionsContextProvider(
  186. auth: auth,
  187. messaging: messagingFake,
  188. appCheck: appCheckFake
  189. )
  190. let expectation = expectation(description: "All contexts available")
  191. provider.getContext { context, error in
  192. XCTAssertNotNil(context)
  193. XCTAssertNil(error)
  194. XCTAssertEqual(context.authToken, "token")
  195. XCTAssertEqual(context.fcmToken, self.messagingFake.fcmToken)
  196. XCTAssertEqual(context.appCheckToken, self.appCheckTokenSuccess.token)
  197. expectation.fulfill()
  198. }
  199. waitForExpectations(timeout: 0.1)
  200. }
  201. func testAsyncAllContextsAuthAndAppCheckError() async {
  202. appCheckFake.tokenResult = appCheckTokenError
  203. let authError = NSError(domain: "com.functions.tests", code: 4, userInfo: nil)
  204. let auth = FIRAuthInteropFake(token: nil, userID: "userID", error: authError)
  205. let provider = FunctionsContextProvider(
  206. auth: auth,
  207. messaging: messagingFake,
  208. appCheck: appCheckFake
  209. )
  210. do {
  211. _ = try await provider.context(options: nil)
  212. XCTFail("Expected an error")
  213. } catch {
  214. XCTAssertEqual(error as NSError, authError)
  215. }
  216. }
  217. func testAllContextsAuthAndAppCheckError() {
  218. appCheckFake.tokenResult = appCheckTokenError
  219. let authError = NSError(domain: "com.functions.tests", code: 4, userInfo: nil)
  220. let auth = FIRAuthInteropFake(token: nil, userID: "userID", error: authError)
  221. let provider = FunctionsContextProvider(
  222. auth: auth,
  223. messaging: messagingFake,
  224. appCheck: appCheckFake
  225. )
  226. let expectation = expectation(description: "All contexts with errors")
  227. provider.getContext { context, error in
  228. XCTAssertNotNil(context)
  229. XCTAssertEqual(error as NSError?, authError)
  230. XCTAssertNil(context.authToken)
  231. XCTAssertEqual(context.fcmToken, self.messagingFake.fcmToken)
  232. // Don't expect any token in the case of App Check error.
  233. XCTAssertNil(context.appCheckToken)
  234. expectation.fulfill()
  235. }
  236. waitForExpectations(timeout: 0.1)
  237. }
  238. }
  239. // MARK: - Utilities
  240. private class AppCheckFakeWithoutOptionalMethods: NSObject, AppCheckInterop {
  241. let tokenResult: FIRAppCheckTokenResultInterop
  242. init(tokenResult: FIRAppCheckTokenResultInterop) {
  243. self.tokenResult = tokenResult
  244. }
  245. func getToken(forcingRefresh: Bool, completion handler: @escaping AppCheckTokenHandlerInterop) {
  246. handler(tokenResult)
  247. }
  248. func tokenDidChangeNotificationName() -> String { "AppCheckFakeTokenDidChangeNotification" }
  249. func notificationTokenKey() -> String { "AppCheckFakeTokenNotificationKey" }
  250. func notificationAppNameKey() -> String { "AppCheckFakeAppNameNotificationKey" }
  251. }