FIRAuthNotificationManagerTests.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <TargetConditionals.h>
  17. #if TARGET_OS_IOS
  18. #import <XCTest/XCTest.h>
  19. #import "OCMock.h"
  20. #import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h"
  21. #import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h"
  22. #import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h"
  23. NS_ASSUME_NONNULL_BEGIN
  24. /** @var kReceipt
  25. @brief A fake receipt used for testing.
  26. */
  27. static NSString *const kReceipt = @"FAKE_RECEIPT";
  28. /** @var kSecret
  29. @brief A fake secret used for testing.
  30. */
  31. static NSString *const kSecret = @"FAKE_SECRET";
  32. /** @class FIRAuthFakeForwardingDelegate
  33. @brief The base class for a fake UIApplicationDelegate that forwards remote notifications.
  34. */
  35. @interface FIRAuthFakeForwardingDelegate : NSObject <UIApplicationDelegate>
  36. /** @property notificationManager
  37. @brief The notification manager to forward.
  38. */
  39. @property(nonatomic, strong) FIRAuthNotificationManager *notificationManager;
  40. /** @property forwardsNotification
  41. @brief Whether notifications are being forwarded.
  42. */
  43. @property(nonatomic, assign) BOOL forwardsNotification;
  44. /** @property notificationReceived
  45. @brief Whether a notification has been received.
  46. */
  47. @property(nonatomic, assign) BOOL notificationReceived;
  48. /** @property notificationhandled
  49. @brief Whether a notification has been handled.
  50. */
  51. @property(nonatomic, assign) BOOL notificationhandled;
  52. @end
  53. @implementation FIRAuthFakeForwardingDelegate
  54. @end
  55. /** @class FIRAuthFakeForwardingDelegate
  56. @brief A fake UIApplicationDelegate that implements the modern deegate method to receive
  57. notification.
  58. */
  59. @interface FIRAuthModernForwardingDelegate : FIRAuthFakeForwardingDelegate
  60. @end
  61. @implementation FIRAuthModernForwardingDelegate
  62. - (void)application:(UIApplication *)application
  63. didReceiveRemoteNotification:(NSDictionary *)userInfo
  64. fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  65. self.notificationReceived = YES;
  66. if (self.forwardsNotification) {
  67. self.notificationhandled = [self.notificationManager canHandleNotification:userInfo];
  68. }
  69. }
  70. @end
  71. /** @class FIRAuthLegacyForwardingDelegate
  72. @brief A fake UIApplicationDelegate that implements the legacy deegate method to receive
  73. notification.
  74. */
  75. @interface FIRAuthLegacyForwardingDelegate : FIRAuthFakeForwardingDelegate
  76. @end
  77. @implementation FIRAuthLegacyForwardingDelegate
  78. - (void)application:(UIApplication *)application
  79. didReceiveRemoteNotification:(NSDictionary *)userInfo {
  80. self.notificationReceived = YES;
  81. if (self.forwardsNotification) {
  82. self.notificationhandled = [self.notificationManager canHandleNotification:userInfo];
  83. }
  84. }
  85. @end
  86. /** @class FIRAuthNotificationManagerTests
  87. @brief Unit tests for @c FIRAuthNotificationManager .
  88. */
  89. @interface FIRAuthNotificationManagerTests : XCTestCase
  90. @end
  91. @implementation FIRAuthNotificationManagerTests {
  92. /** @var _mockApplication
  93. @brief The mock UIApplication for testing.
  94. */
  95. id _mockApplication;
  96. /** @var _mockAppCredentialManager
  97. @brief The mock FIRAuthAppCredentialManager for testing.
  98. */
  99. id _mockAppCredentialManager;
  100. /** @var _notificationManager
  101. @brief The FIRAuthNotificationManager to be tested.
  102. */
  103. FIRAuthNotificationManager *_notificationManager;
  104. /** @var _modernDelegate
  105. @brief The modern fake UIApplicationDelegate for testing.
  106. */
  107. FIRAuthModernForwardingDelegate *_modernDelegate;
  108. /** @var _legacyDelegate
  109. @brief The legacy fake UIApplicationDelegate for testing.
  110. */
  111. FIRAuthLegacyForwardingDelegate *_legacyDelegate;
  112. }
  113. - (void)setUp {
  114. _mockApplication = OCMClassMock([UIApplication class]);
  115. _mockAppCredentialManager = OCMClassMock([FIRAuthAppCredentialManager class]);
  116. _notificationManager =
  117. [[FIRAuthNotificationManager alloc] initWithApplication:_mockApplication
  118. appCredentialManager:_mockAppCredentialManager];
  119. _modernDelegate = [[FIRAuthModernForwardingDelegate alloc] init];
  120. _modernDelegate.notificationManager = _notificationManager;
  121. _legacyDelegate = [[FIRAuthLegacyForwardingDelegate alloc] init];
  122. _legacyDelegate.notificationManager = _notificationManager;
  123. }
  124. /** @fn testForwardingModernDelegate
  125. @brief Tests checking notification forwarding on modern fake delegate.
  126. */
  127. - (void)testForwardingModernDelegate {
  128. [self verifyForwarding:YES delegate:_modernDelegate];
  129. }
  130. /** @fn testForwardingLegacyDelegate
  131. @brief Tests checking notification forwarding on legacy fake delegate.
  132. */
  133. - (void)testForwardingLegacyDelegate {
  134. [self verifyForwarding:YES delegate:_legacyDelegate];
  135. }
  136. /** @fn testNotForwardingModernDelegate
  137. @brief Tests checking notification not forwarding on modern fake delegate.
  138. */
  139. - (void)testNotForwardingModernDelegate {
  140. [self verifyForwarding:NO delegate:_modernDelegate];
  141. }
  142. /** @fn testNotForwardingLegacyDelegate
  143. @brief Tests checking notification not forwarding on legacy fake delegate.
  144. */
  145. - (void)testNotForwardingLegacyDelegate {
  146. [self verifyForwarding:NO delegate:_legacyDelegate];
  147. }
  148. /** @fn verifyForwarding:delegate:
  149. @brief Tests checking notification forwarding on a particular delegate.
  150. @param forwarding Whether the notification is being forwarded or not.
  151. @param delegate The fake UIApplicationDelegate used for testing.
  152. */
  153. - (void)verifyForwarding:(BOOL)forwarding delegate:(FIRAuthFakeForwardingDelegate *)delegate {
  154. delegate.forwardsNotification = forwarding;
  155. OCMStub([_mockApplication delegate]).andReturn(delegate);
  156. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  157. [_notificationManager
  158. checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) {
  159. XCTAssertEqual(isNotificationBeingForwarded, forwarding);
  160. [expectation fulfill];
  161. }];
  162. XCTAssertFalse(delegate.notificationReceived);
  163. NSTimeInterval timeout = _notificationManager.timeout * (1.5 - forwarding);
  164. [self waitForExpectationsWithTimeout:timeout handler:nil];
  165. XCTAssertTrue(delegate.notificationReceived);
  166. XCTAssertEqual(delegate.notificationhandled, forwarding);
  167. }
  168. /** @fn testCachedResult
  169. @brief Test notification forwarding is only checked once.
  170. */
  171. - (void)testCachedResult {
  172. FIRAuthFakeForwardingDelegate *delegate = _modernDelegate;
  173. [self verifyForwarding:NO delegate:delegate];
  174. delegate.notificationReceived = NO;
  175. __block BOOL calledBack = NO;
  176. [_notificationManager
  177. checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) {
  178. XCTAssertFalse(isNotificationBeingForwarded);
  179. calledBack = YES;
  180. }];
  181. XCTAssertTrue(calledBack);
  182. XCTAssertFalse(delegate.notificationReceived);
  183. }
  184. /** @fn testMultipleCallbacks
  185. @brief Test multiple callbacks are handled correctly.
  186. */
  187. - (void)testMultipleCallbacks {
  188. FIRAuthFakeForwardingDelegate *delegate = _legacyDelegate;
  189. delegate.forwardsNotification = YES;
  190. OCMStub([_mockApplication delegate]).andReturn(delegate);
  191. XCTestExpectation *expectation1 = [self expectationWithDescription:@"callback1"];
  192. [_notificationManager
  193. checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) {
  194. XCTAssertTrue(isNotificationBeingForwarded);
  195. [expectation1 fulfill];
  196. }];
  197. XCTestExpectation *expectation2 = [self expectationWithDescription:@"callback2"];
  198. [_notificationManager
  199. checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) {
  200. XCTAssertTrue(isNotificationBeingForwarded);
  201. [expectation2 fulfill];
  202. }];
  203. XCTAssertFalse(delegate.notificationReceived);
  204. [self waitForExpectationsWithTimeout:_notificationManager.timeout * .5 handler:nil];
  205. XCTAssertTrue(delegate.notificationReceived);
  206. XCTAssertTrue(delegate.notificationhandled);
  207. }
  208. /** @fn testPassingToCredentialManager
  209. @brief Test notification with the right structure is passed to credential manager.
  210. */
  211. - (void)testPassingToCredentialManager {
  212. NSDictionary *payload = @{@"receipt" : kReceipt, @"secret" : kSecret};
  213. NSDictionary *notification = @{@"com.google.firebase.auth" : payload};
  214. OCMExpect([_mockAppCredentialManager canFinishVerificationWithReceipt:kReceipt secret:kSecret])
  215. .andReturn(YES);
  216. XCTAssertTrue([_notificationManager canHandleNotification:notification]);
  217. OCMVerifyAll(_mockAppCredentialManager);
  218. // JSON string form
  219. NSData *data = [NSJSONSerialization dataWithJSONObject:payload options:0 error:NULL];
  220. NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  221. notification = @{@"com.google.firebase.auth" : string};
  222. OCMExpect([_mockAppCredentialManager canFinishVerificationWithReceipt:kReceipt secret:kSecret])
  223. .andReturn(YES);
  224. XCTAssertTrue([_notificationManager canHandleNotification:notification]);
  225. OCMVerifyAll(_mockAppCredentialManager);
  226. }
  227. /** @fn testNotHandling
  228. @brief Test unrecognized notifications are not handled.
  229. */
  230. - (void)testNotHandling {
  231. XCTAssertFalse([_notificationManager canHandleNotification:@{@"random" : @"string"}]);
  232. XCTAssertFalse([_notificationManager
  233. canHandleNotification:@{@"com.google.firebase.auth" : @"something wrong"}]);
  234. XCTAssertFalse([_notificationManager canHandleNotification:@{
  235. @"com.google.firebase.auth" : @{
  236. @"receipt" : kReceipt
  237. // missing secret
  238. }
  239. }]);
  240. XCTAssertFalse([_notificationManager canHandleNotification:@{
  241. @"com.google.firebase.auth" : @{
  242. // missing receipt
  243. @"secret" : kSecret
  244. }
  245. }]);
  246. XCTAssertFalse([_notificationManager canHandleNotification:@{
  247. @"com.google.firebase.auth" : @{
  248. // probing notification does not belong to this instance
  249. @"warning" : @"asdf"
  250. }
  251. }]);
  252. }
  253. @end
  254. NS_ASSUME_NONNULL_END
  255. #endif