AuthAppCredentialManagerTests.swift 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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(macOS)
  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 AuthAppCredentialManagerTests: XCTestCase {
  20. let kReceipt = "FAKE_RECEIPT"
  21. let kVerificationTimeout = 1.0
  22. let kSecret = "FAKE_SECRET"
  23. let kAnotherReceipt = "OTHER_RECEIPT"
  24. let kAnotherSecret = "OTHER_SECRET"
  25. /** @fn testCompletion
  26. @brief Tests a successfully completed verification flow.
  27. */
  28. func testCompletion() {
  29. let fakeKeychain = AuthKeychainServices(
  30. service: "AuthAppCredentialManagerTests",
  31. storage: FakeAuthKeychainStorage()
  32. )
  33. let manager = AuthAppCredentialManager(withKeychain: fakeKeychain)
  34. XCTAssertNil(manager.credential)
  35. // Start verification.
  36. let expectation = self.expectation(description: #function)
  37. manager.didStartVerificationInternal(withReceipt: kReceipt,
  38. timeout: kVerificationTimeout) { [self] credential in
  39. XCTAssertEqual(credential.receipt, self.kReceipt)
  40. XCTAssertEqual(credential.secret, self.kSecret)
  41. expectation.fulfill()
  42. }
  43. XCTAssertNil(manager.credential)
  44. // Mismatched receipt shouldn't finish verification.
  45. XCTAssertFalse(manager
  46. .canFinishVerification(withReceipt: kAnotherReceipt, secret: kAnotherSecret))
  47. XCTAssertNil(manager.credential)
  48. // Finish verification.
  49. XCTAssertTrue(manager.canFinishVerification(withReceipt: kReceipt, secret: kSecret))
  50. waitForExpectations(timeout: 5)
  51. XCTAssertEqual(manager.credential?.receipt, kReceipt)
  52. XCTAssertEqual(manager.credential?.secret, kSecret)
  53. // Repeated receipt should have no effect.
  54. XCTAssertFalse(manager.canFinishVerification(withReceipt: kReceipt, secret: kSecret))
  55. XCTAssertEqual(manager.credential?.secret, kSecret)
  56. }
  57. /** @fn testTimeout
  58. @brief Tests a verification flow that times out.
  59. */
  60. func testTimeout() {
  61. let fakeKeychain = AuthKeychainServices(
  62. service: "AuthAppCredentialManagerTests",
  63. storage: FakeAuthKeychainStorage()
  64. )
  65. let manager = AuthAppCredentialManager(withKeychain: fakeKeychain)
  66. XCTAssertNil(manager.credential)
  67. // Start verification.
  68. let expectation = self.expectation(description: #function)
  69. manager.didStartVerificationInternal(withReceipt: kReceipt,
  70. timeout: kVerificationTimeout) { [self] credential in
  71. XCTAssertEqual(credential.receipt, self.kReceipt)
  72. XCTAssertNil(credential.secret) // different from test above.
  73. expectation.fulfill()
  74. }
  75. XCTAssertNil(manager.credential)
  76. // Timeout
  77. waitForExpectations(timeout: 5)
  78. // Finish verification.
  79. XCTAssertTrue(manager.canFinishVerification(withReceipt: kReceipt, secret: kSecret))
  80. XCTAssertEqual(manager.credential?.receipt, kReceipt)
  81. XCTAssertEqual(manager.credential?.secret, kSecret)
  82. }
  83. /** @fn testMaximumPendingReceipt
  84. @brief Tests the maximum allowed number of pending receipt.
  85. */
  86. func testMaximumPendingReceipt() {
  87. let fakeKeychain = AuthKeychainServices(
  88. service: "AuthAppCredentialManagerTests",
  89. storage: FakeAuthKeychainStorage()
  90. )
  91. let manager = AuthAppCredentialManager(withKeychain: fakeKeychain)
  92. XCTAssertNil(manager.credential)
  93. // Start verification.
  94. let expectation = self.expectation(description: #function)
  95. manager.didStartVerificationInternal(withReceipt: kReceipt,
  96. timeout: kVerificationTimeout) { [self] credential in
  97. XCTAssertEqual(credential.receipt, self.kReceipt)
  98. XCTAssertEqual(credential.secret, self.kSecret)
  99. expectation.fulfill()
  100. }
  101. XCTAssertNil(manager.credential)
  102. // Start verification of a number of random receipts without overflowing.
  103. for i in 1 ... (manager.maximumNumberOfPendingReceipts - 1) {
  104. let randomReceipt = "RANDOM_\(i)"
  105. let randomExpectation = self.expectation(description: randomReceipt)
  106. manager.didStartVerificationInternal(withReceipt: randomReceipt,
  107. timeout: kVerificationTimeout) { credential in
  108. // They all should get full credential because one is
  109. // available at this point.
  110. XCTAssertEqual(credential.receipt, self.kReceipt)
  111. XCTAssertEqual(credential.secret, self.kSecret)
  112. randomExpectation.fulfill()
  113. }
  114. }
  115. // Finish verification of target receipt.
  116. XCTAssertTrue(manager.canFinishVerification(withReceipt: kReceipt, secret: kSecret))
  117. waitForExpectations(timeout: 5)
  118. XCTAssertEqual(manager.credential?.receipt, kReceipt)
  119. XCTAssertEqual(manager.credential?.secret, kSecret)
  120. // Clear credential to prepare for next round.
  121. manager.clearCredential()
  122. XCTAssertNil(manager.credential)
  123. // Start verification of another target receipt.
  124. let anotherExpectation = self.expectation(description: "another")
  125. manager.didStartVerificationInternal(withReceipt: kAnotherReceipt,
  126. timeout: kVerificationTimeout) { [self] credential in
  127. XCTAssertEqual(credential.receipt, self.kAnotherReceipt)
  128. XCTAssertNil(credential.secret)
  129. anotherExpectation.fulfill()
  130. }
  131. XCTAssertNil(manager.credential)
  132. // Start verification of a number of random receipts to overflow.
  133. for i in 1 ... manager.maximumNumberOfPendingReceipts {
  134. let randomReceipt = "RANDOM_\(i)"
  135. let randomExpectation = self.expectation(description: randomReceipt)
  136. manager.didStartVerificationInternal(withReceipt: randomReceipt,
  137. timeout: kVerificationTimeout) { credential in
  138. // They all should get partial credential because verification
  139. // has never completed.
  140. XCTAssertEqual(credential.receipt, randomReceipt)
  141. XCTAssertNil(credential.secret)
  142. randomExpectation.fulfill()
  143. }
  144. }
  145. // Finish verification of the other target receipt.
  146. XCTAssertFalse(manager
  147. .canFinishVerification(withReceipt: kAnotherReceipt, secret: kAnotherSecret))
  148. waitForExpectations(timeout: 5)
  149. XCTAssertNil(manager.credential)
  150. }
  151. /** @fn testKeychain
  152. @brief Tests state preservation in the keychain.
  153. */
  154. func testKeychain() {
  155. let fakeKeychain = AuthKeychainServices(
  156. service: "AuthAppCredentialManagerTests",
  157. storage: FakeAuthKeychainStorage()
  158. )
  159. let manager = AuthAppCredentialManager(withKeychain: fakeKeychain)
  160. XCTAssertNil(manager.credential)
  161. // Start verification.
  162. let expectation = self.expectation(description: #function)
  163. manager.didStartVerificationInternal(withReceipt: kReceipt,
  164. timeout: kVerificationTimeout) { [self] credential in
  165. XCTAssertEqual(credential.receipt, self.kReceipt)
  166. XCTAssertNil(credential.secret)
  167. expectation.fulfill()
  168. }
  169. XCTAssertNil(manager.credential)
  170. // Timeout
  171. waitForExpectations(timeout: 5)
  172. // Start a new manager with saved data in keychain.
  173. let manager2 = AuthAppCredentialManager(withKeychain: fakeKeychain)
  174. XCTAssertNil(manager2.credential)
  175. // Finish verification.
  176. XCTAssertTrue(manager2.canFinishVerification(withReceipt: kReceipt, secret: kSecret))
  177. XCTAssertEqual(manager2.credential?.receipt, kReceipt)
  178. XCTAssertEqual(manager2.credential?.secret, kSecret)
  179. // Start yet another new manager with saved data in keychain.
  180. let manager3 = AuthAppCredentialManager(withKeychain: fakeKeychain)
  181. XCTAssertNotNil(manager3.credential)
  182. XCTAssertEqual(manager3.credential?.receipt, kReceipt)
  183. XCTAssertEqual(manager3.credential?.secret, kSecret)
  184. }
  185. }
  186. #endif