AuthNotificationManagerTests.swift 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2023 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. #if os(iOS)
  15. import Foundation
  16. import XCTest
  17. @testable import FirebaseAuth
  18. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  19. class AuthNotificationManagerTests: XCTestCase {
  20. /** @var kReceipt
  21. @brief A fake receipt used for testing.
  22. */
  23. private let kReceipt = "FAKE_RECEIPT"
  24. /** @var kSecret
  25. @brief A fake secret used for testing.
  26. */
  27. private let kSecret = "FAKE_SECRET"
  28. /** @property notificationManager
  29. @brief The notification manager to forward.
  30. */
  31. private var notificationManager: AuthNotificationManager?
  32. /** @var modernDelegate
  33. @brief The modern fake UIApplicationDelegate for testing.
  34. */
  35. private var modernDelegate: FakeForwardingDelegate?
  36. /** @var appCredentialManager
  37. @brief A stubbed AppCredentialManager for testing.
  38. */
  39. private var appCredentialManager: AuthAppCredentialManager?
  40. override func setUp() {
  41. let fakeKeychain = AuthKeychainServices(
  42. service: "AuthNotificationManagerTests",
  43. storage: FakeAuthKeychainStorage()
  44. )
  45. appCredentialManager = AuthAppCredentialManager(withKeychain: fakeKeychain)
  46. let application = UIApplication.shared
  47. notificationManager = AuthNotificationManager(withApplication: application,
  48. appCredentialManager: appCredentialManager!)
  49. modernDelegate = FakeForwardingDelegate(notificationManager!)
  50. application.delegate = modernDelegate
  51. }
  52. /** @fn testForwardingModernDelegate
  53. @brief Tests checking notification forwarding on modern fake delegate.
  54. */
  55. func testForwardingModernDelegate() throws {
  56. try verify(forwarding: true, delegate: XCTUnwrap(modernDelegate))
  57. }
  58. /** @fn testNotForwardingModernDelegate
  59. @brief Tests checking notification not forwarding on modern fake delegate.
  60. */
  61. func testNotForwardingModernDelegate() throws {
  62. try verify(forwarding: false, delegate: XCTUnwrap(modernDelegate))
  63. }
  64. private func verify(forwarding: Bool, delegate: FakeForwardingDelegate) throws {
  65. delegate.forwardsNotification = forwarding
  66. let expectation = self.expectation(description: "callback")
  67. notificationManager?.checkNotificationForwardingInternal { forwarded in
  68. XCTAssertEqual(forwarded, forwarding)
  69. expectation.fulfill()
  70. }
  71. XCTAssertFalse(delegate.notificationReceived)
  72. let timeout = try XCTUnwrap(notificationManager?.timeout) * (forwarding ? 0.5 : 1.5)
  73. waitForExpectations(timeout: timeout)
  74. XCTAssertTrue(delegate.notificationReceived)
  75. XCTAssertEqual(delegate.notificationHandled, forwarding)
  76. }
  77. /** @fn testCachedResult
  78. @brief Test notification forwarding is only checked once.
  79. */
  80. func testCachedResult() throws {
  81. let delegate = try XCTUnwrap(modernDelegate)
  82. try verify(forwarding: false, delegate: delegate)
  83. modernDelegate?.notificationReceived = false
  84. var calledBack = false
  85. notificationManager?.checkNotificationForwardingInternal { isNotificationBeingForwarded in
  86. XCTAssertFalse(isNotificationBeingForwarded)
  87. calledBack = true
  88. }
  89. XCTAssertTrue(calledBack)
  90. XCTAssertFalse(delegate.notificationReceived)
  91. }
  92. /** @fn testPassingToCredentialManager
  93. @brief Test notification with the right structure is passed to credential manager.
  94. */
  95. func testPassingToCredentialManager() async throws {
  96. let payload = ["receipt": kReceipt, "secret": kSecret]
  97. let notification = ["com.google.firebase.auth": payload]
  98. // Stub appCredentialManager
  99. let _ = await appCredentialManager?.didStartVerification(withReceipt: kReceipt, timeout: 0)
  100. XCTAssertTrue(try XCTUnwrap(notificationManager?.canHandle(notification: notification)))
  101. // JSON string form
  102. let data = try JSONSerialization.data(withJSONObject: payload)
  103. let string = String(data: data, encoding: .utf8)
  104. let jsonNotification = ["com.google.firebase.auth": string as Any] as [AnyHashable: Any]
  105. let _ = await appCredentialManager?.didStartVerification(withReceipt: kReceipt, timeout: 0)
  106. XCTAssertTrue(try XCTUnwrap(notificationManager?.canHandle(notification: jsonNotification)))
  107. }
  108. /** @fn testNotHandling
  109. @brief Test unrecognized notifications are not handled.
  110. */
  111. func testNotHandling() throws {
  112. let manager = try XCTUnwrap(notificationManager)
  113. XCTAssertFalse(manager.canHandle(notification: ["random": "string"]))
  114. XCTAssertFalse(manager
  115. .canHandle(notification: ["com.google.firebase.auth": "something wrong"]))
  116. // Missing secret.
  117. XCTAssertFalse(manager
  118. .canHandle(notification: ["com.google.firebase.auth": ["receipt": kReceipt]]))
  119. // Missing receipt.
  120. XCTAssertFalse(manager
  121. .canHandle(notification: ["com.google.firebase.auth": ["secret": kSecret]]))
  122. // Probing notification does not belong to this instance.
  123. XCTAssertFalse(manager
  124. .canHandle(notification: ["com.google.firebase.auth": ["warning": "asdf"]]))
  125. }
  126. private class FakeApplication: UIApplication {}
  127. private class FakeForwardingDelegate: NSObject, UIApplicationDelegate {
  128. let notificationManager: AuthNotificationManager
  129. var forwardsNotification = false
  130. var notificationReceived = false
  131. var notificationHandled = false
  132. init(_ notificationManager: AuthNotificationManager, forwardsNotification: Bool = false,
  133. notificationReceived: Bool = false, notificationHandled: Bool = false) {
  134. self.notificationManager = notificationManager
  135. self.forwardsNotification = forwardsNotification
  136. self.notificationReceived = notificationReceived
  137. self.notificationHandled = notificationHandled
  138. }
  139. func application(_ application: UIApplication,
  140. didReceiveRemoteNotification userInfo: [AnyHashable: Any],
  141. fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult)
  142. -> Void) {
  143. notificationReceived = true
  144. if forwardsNotification {
  145. notificationHandled = notificationManager.canHandle(notification: userInfo)
  146. }
  147. }
  148. }
  149. }
  150. #endif