AuthNotificationManagerTests.swift 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. Task {
  68. let forwarded = await notificationManager.checkNotificationForwarding()
  69. XCTAssertEqual(forwarded, forwarding)
  70. expectation.fulfill()
  71. }
  72. XCTAssertFalse(delegate.notificationReceived)
  73. let timeout = try XCTUnwrap(notificationManager?.timeout) * (forwarding ? 0.5 : 1.5)
  74. waitForExpectations(timeout: timeout)
  75. XCTAssertTrue(delegate.notificationReceived)
  76. XCTAssertEqual(delegate.notificationHandled, forwarding)
  77. }
  78. /** @fn testCachedResult
  79. @brief Test notification forwarding is only checked once.
  80. */
  81. func testCachedResult() throws {
  82. let delegate = try XCTUnwrap(modernDelegate)
  83. try verify(forwarding: false, delegate: delegate)
  84. modernDelegate?.notificationReceived = false
  85. let expectation = self.expectation(description: "callback")
  86. Task {
  87. let isNotificationBeingForwarded = await notificationManager.checkNotificationForwarding()
  88. XCTAssertFalse(isNotificationBeingForwarded)
  89. expectation.fulfill()
  90. }
  91. waitForExpectations(timeout: 5)
  92. XCTAssertFalse(delegate.notificationReceived)
  93. }
  94. /** @fn testPassingToCredentialManager
  95. @brief Test notification with the right structure is passed to credential manager.
  96. */
  97. func testPassingToCredentialManager() async throws {
  98. let payload = ["receipt": kReceipt, "secret": kSecret]
  99. let notification = ["com.google.firebase.auth": payload]
  100. // Stub appCredentialManager
  101. let _ = await appCredentialManager?.didStartVerification(withReceipt: kReceipt, timeout: 0)
  102. XCTAssertTrue(try XCTUnwrap(notificationManager?.canHandle(notification: notification)))
  103. // JSON string form
  104. let data = try JSONSerialization.data(withJSONObject: payload)
  105. let string = String(data: data, encoding: .utf8)
  106. let jsonNotification = ["com.google.firebase.auth": string as Any] as [AnyHashable: Any]
  107. let _ = await appCredentialManager?.didStartVerification(withReceipt: kReceipt, timeout: 0)
  108. XCTAssertTrue(try XCTUnwrap(notificationManager?.canHandle(notification: jsonNotification)))
  109. }
  110. /** @fn testNotHandling
  111. @brief Test unrecognized notifications are not handled.
  112. */
  113. func testNotHandling() throws {
  114. let manager = try XCTUnwrap(notificationManager)
  115. XCTAssertFalse(manager.canHandle(notification: ["random": "string"]))
  116. XCTAssertFalse(manager
  117. .canHandle(notification: ["com.google.firebase.auth": "something wrong"]))
  118. // Missing secret.
  119. XCTAssertFalse(manager
  120. .canHandle(notification: ["com.google.firebase.auth": ["receipt": kReceipt]]))
  121. // Missing receipt.
  122. XCTAssertFalse(manager
  123. .canHandle(notification: ["com.google.firebase.auth": ["secret": kSecret]]))
  124. // Probing notification does not belong to this instance.
  125. XCTAssertFalse(manager
  126. .canHandle(notification: ["com.google.firebase.auth": ["error": "asdf"]]))
  127. }
  128. private class FakeApplication: UIApplication {}
  129. private class FakeForwardingDelegate: NSObject, UIApplicationDelegate {
  130. let notificationManager: AuthNotificationManager
  131. var forwardsNotification = false
  132. var notificationReceived = false
  133. var notificationHandled = false
  134. init(_ notificationManager: AuthNotificationManager, forwardsNotification: Bool = false,
  135. notificationReceived: Bool = false, notificationHandled: Bool = false) {
  136. self.notificationManager = notificationManager
  137. self.forwardsNotification = forwardsNotification
  138. self.notificationReceived = notificationReceived
  139. self.notificationHandled = notificationHandled
  140. }
  141. func application(_ application: UIApplication,
  142. didReceiveRemoteNotification userInfo: [AnyHashable: Any],
  143. fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult)
  144. -> Void) {
  145. notificationReceived = true
  146. if forwardsNotification {
  147. notificationHandled = notificationManager.canHandle(notification: userInfo)
  148. }
  149. }
  150. }
  151. }
  152. #endif