FIRMessagingContextManagerServiceTest.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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 <OCMock/OCMock.h>
  17. #import <UserNotifications/UserNotifications.h>
  18. #import <XCTest/XCTest.h>
  19. #import "FirebaseMessaging/Sources/FIRMessagingContextManagerService.h"
  20. static NSString *const kBody = @"Save 20% off!";
  21. static NSString *const kTitle = @"Sparky WFH";
  22. static NSString *const kSoundName = @"default";
  23. static NSString *const kAction = @"open";
  24. static NSString *const kUserInfoKey1 = @"level";
  25. static NSString *const kUserInfoKey2 = @"isPayUser";
  26. static NSString *const kUserInfoValue1 = @"5";
  27. static NSString *const kUserInfoValue2 = @"Yes";
  28. static NSString *const kMessageIdentifierKey = @"gcm.message_id";
  29. static NSString *const kMessageIdentifierValue = @"1584748495200141";
  30. @interface FIRMessagingContextManagerService (ExposedForTest)
  31. + (void)scheduleiOS10LocalNotificationForMessage:(NSDictionary *)message atDate:(NSDate *)date;
  32. + (UNMutableNotificationContent *)contentFromContextualMessage:(NSDictionary *)message
  33. API_AVAILABLE(macos(10.14));
  34. @end
  35. API_AVAILABLE(macos(10.14))
  36. @interface FIRMessagingContextManagerServiceTest : XCTestCase
  37. @property(nonatomic, readwrite, strong) NSDateFormatter *dateFormatter;
  38. @property(nonatomic, readwrite, strong) NSMutableArray *scheduledLocalNotifications;
  39. @property(nonatomic, readwrite, strong) NSMutableArray<UNNotificationRequest *> *requests;
  40. @end
  41. @implementation FIRMessagingContextManagerServiceTest
  42. - (void)setUp {
  43. [super setUp];
  44. self.dateFormatter = [[NSDateFormatter alloc] init];
  45. self.dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
  46. [self.dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  47. self.scheduledLocalNotifications = [[NSMutableArray alloc] init];
  48. if (@available(macOS 10.14, *)) {
  49. self.requests = [[NSMutableArray alloc] init];
  50. }
  51. [self mockSchedulingLocalNotifications];
  52. }
  53. - (void)tearDown {
  54. [super tearDown];
  55. }
  56. /**
  57. * Test invalid context manager message, missing lt_start string.
  58. */
  59. - (void)testInvalidContextManagerMessage_missingStartTime {
  60. NSDictionary *message = @{
  61. @"hello" : @"world",
  62. };
  63. XCTAssertFalse([FIRMessagingContextManagerService isContextManagerMessage:message]);
  64. }
  65. /**
  66. * Test valid context manager message.
  67. */
  68. - (void)testValidContextManagerMessage {
  69. NSDictionary *message = @{
  70. kFIRMessagingContextManagerLocalTimeStart : @"2015-12-12 00:00:00",
  71. @"hello" : @"world",
  72. };
  73. XCTAssertTrue([FIRMessagingContextManagerService isContextManagerMessage:message]);
  74. }
  75. /**
  76. * Context Manager message with future start date should be successfully scheduled.
  77. */
  78. - (void)testMessageWithFutureStartTime {
  79. // way into the future
  80. NSString *startTimeString = [self.dateFormatter stringFromDate:[NSDate distantFuture]];
  81. NSDictionary *message = @{
  82. kFIRMessagingContextManagerLocalTimeStart : startTimeString,
  83. kFIRMessagingContextManagerBodyKey : kBody,
  84. kMessageIdentifierKey : kMessageIdentifierValue,
  85. kUserInfoKey1 : kUserInfoValue1,
  86. kUserInfoKey2 : kUserInfoValue2
  87. };
  88. XCTAssertTrue([FIRMessagingContextManagerService handleContextManagerMessage:message]);
  89. if (@available(macOS 10.14, *)) {
  90. XCTAssertEqual(self.requests.count, 1);
  91. UNNotificationRequest *request = self.requests.firstObject;
  92. XCTAssertEqualObjects(request.identifier, kMessageIdentifierValue);
  93. #if !TARGET_OS_TV
  94. XCTAssertEqualObjects(request.content.body, kBody);
  95. XCTAssertEqualObjects(request.content.userInfo[kUserInfoKey1], kUserInfoValue1);
  96. XCTAssertEqualObjects(request.content.userInfo[kUserInfoKey2], kUserInfoValue2);
  97. #endif // TARGET_OS_TV
  98. return;
  99. }
  100. #if TARGET_OS_IOS
  101. XCTAssertEqual(self.scheduledLocalNotifications.count, 1);
  102. #pragma clang diagnostic push
  103. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  104. UILocalNotification *notification = self.scheduledLocalNotifications.firstObject;
  105. #pragma clang diagnostic pop
  106. NSDate *date = [self.dateFormatter dateFromString:startTimeString];
  107. XCTAssertEqual([notification.fireDate compare:date], NSOrderedSame);
  108. XCTAssertEqualObjects(notification.alertBody, kBody);
  109. XCTAssertEqualObjects(notification.userInfo[kUserInfoKey1], kUserInfoValue1);
  110. XCTAssertEqualObjects(notification.userInfo[kUserInfoKey2], kUserInfoValue2);
  111. #endif // TARGET_OS_IOS
  112. }
  113. /**
  114. * Context Manager message with past end date should not be scheduled.
  115. */
  116. - (void)testMessageWithPastEndTime {
  117. #if TARGET_OS_IOS
  118. NSString *startTimeString = @"2010-01-12 12:00:00"; // way into the past
  119. NSString *endTimeString = @"2011-01-12 12:00:00"; // way into the past
  120. NSDictionary *message = @{
  121. kFIRMessagingContextManagerLocalTimeStart : startTimeString,
  122. kFIRMessagingContextManagerLocalTimeEnd : endTimeString,
  123. kFIRMessagingContextManagerBodyKey : kBody,
  124. kMessageIdentifierKey : kMessageIdentifierValue,
  125. @"hello" : @"world"
  126. };
  127. XCTAssertTrue([FIRMessagingContextManagerService handleContextManagerMessage:message]);
  128. if (@available(macOS 10.14, *)) {
  129. XCTAssertEqual(self.requests.count, 0);
  130. return;
  131. }
  132. XCTAssertEqual(self.scheduledLocalNotifications.count, 0);
  133. #endif
  134. }
  135. /**
  136. * Context Manager message with past start and future end date should be successfully
  137. * scheduled.
  138. */
  139. - (void)testMessageWithPastStartAndFutureEndTime {
  140. #if TARGET_OS_IOS
  141. NSDate *startDate = [NSDate dateWithTimeIntervalSinceNow:-1000]; // past
  142. NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:1000]; // future
  143. NSString *startTimeString = [self.dateFormatter stringFromDate:startDate];
  144. NSString *endTimeString = [self.dateFormatter stringFromDate:endDate];
  145. NSDictionary *message = @{
  146. kFIRMessagingContextManagerLocalTimeStart : startTimeString,
  147. kFIRMessagingContextManagerLocalTimeEnd : endTimeString,
  148. kFIRMessagingContextManagerBodyKey : kBody,
  149. kMessageIdentifierKey : kMessageIdentifierValue,
  150. kUserInfoKey1 : kUserInfoValue1,
  151. kUserInfoKey2 : kUserInfoValue2
  152. };
  153. XCTAssertTrue([FIRMessagingContextManagerService handleContextManagerMessage:message]);
  154. if (@available(macOS 10.14, *)) {
  155. XCTAssertEqual(self.requests.count, 1);
  156. UNNotificationRequest *request = self.requests.firstObject;
  157. XCTAssertEqualObjects(request.identifier, kMessageIdentifierValue);
  158. XCTAssertEqualObjects(request.content.body, kBody);
  159. XCTAssertEqualObjects(request.content.userInfo[kUserInfoKey1], kUserInfoValue1);
  160. XCTAssertEqualObjects(request.content.userInfo[kUserInfoKey2], kUserInfoValue2);
  161. return;
  162. }
  163. XCTAssertEqual(self.scheduledLocalNotifications.count, 1);
  164. #pragma clang diagnostic push
  165. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  166. UILocalNotification *notification = [self.scheduledLocalNotifications firstObject];
  167. #pragma clang diagnostic pop
  168. // schedule notification after start date
  169. XCTAssertEqual([notification.fireDate compare:startDate], NSOrderedDescending);
  170. // schedule notification after end date
  171. XCTAssertEqual([notification.fireDate compare:endDate], NSOrderedAscending);
  172. XCTAssertEqualObjects(notification.userInfo[kUserInfoKey1], kUserInfoValue1);
  173. XCTAssertEqualObjects(notification.userInfo[kUserInfoKey2], kUserInfoValue2);
  174. #endif // TARGET_OS_IOS
  175. }
  176. /**
  177. * Test correctly parsing user data in local notifications.
  178. */
  179. - (void)testTimedNotificationsUserInfo {
  180. #if TARGET_OS_IOS
  181. // way into the future
  182. NSString *startTimeString = [self.dateFormatter stringFromDate:[NSDate distantFuture]];
  183. NSDictionary *message = @{
  184. kFIRMessagingContextManagerLocalTimeStart : startTimeString,
  185. kFIRMessagingContextManagerBodyKey : kBody,
  186. kMessageIdentifierKey : kMessageIdentifierValue,
  187. kUserInfoKey1 : kUserInfoValue1,
  188. kUserInfoKey2 : kUserInfoValue2
  189. };
  190. XCTAssertTrue([FIRMessagingContextManagerService handleContextManagerMessage:message]);
  191. if (@available(macOS 10.14, *)) {
  192. XCTAssertEqual(self.requests.count, 1);
  193. UNNotificationRequest *request = self.requests.firstObject;
  194. XCTAssertEqualObjects(request.identifier, kMessageIdentifierValue);
  195. XCTAssertEqualObjects(request.content.body, kBody);
  196. XCTAssertEqualObjects(request.content.userInfo[kUserInfoKey1], kUserInfoValue1);
  197. XCTAssertEqualObjects(request.content.userInfo[kUserInfoKey2], kUserInfoValue2);
  198. return;
  199. }
  200. XCTAssertEqual(self.scheduledLocalNotifications.count, 1);
  201. #pragma clang diagnostic push
  202. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  203. UILocalNotification *notification = [self.scheduledLocalNotifications firstObject];
  204. #pragma clang diagnostic pop
  205. XCTAssertEqualObjects(notification.userInfo[kUserInfoKey1], kUserInfoValue1);
  206. XCTAssertEqualObjects(notification.userInfo[kUserInfoKey2], kUserInfoValue2);
  207. #endif // TARGET_OS_IOS
  208. }
  209. #pragma mark - Private Helpers
  210. - (void)mockSchedulingLocalNotifications {
  211. if (@available(macOS 10.14, iOS 10.0, watchOS 3.0, tvOS 10.0, *)) {
  212. id mockNotificationCenter =
  213. OCMPartialMock([UNUserNotificationCenter currentNotificationCenter]);
  214. __block UNNotificationRequest *request;
  215. [[[mockNotificationCenter stub] andDo:^(NSInvocation *invocation) {
  216. [self.requests addObject:request];
  217. }] addNotificationRequest:[OCMArg checkWithBlock:^BOOL(id obj) {
  218. if ([obj isKindOfClass:[UNNotificationRequest class]]) {
  219. request = obj;
  220. [self.requests addObject:request];
  221. return YES;
  222. }
  223. return NO;
  224. }]
  225. withCompletionHandler:^(NSError *_Nullable error){
  226. }];
  227. return;
  228. }
  229. #if TARGET_OS_IOS
  230. id mockApplication = OCMPartialMock([UIApplication sharedApplication]);
  231. #pragma clang diagnostic push
  232. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  233. __block UILocalNotification *notificationToSchedule;
  234. [[[mockApplication stub] andDo:^(NSInvocation *invocation) {
  235. // Mock scheduling a notification
  236. if (notificationToSchedule) {
  237. [self.scheduledLocalNotifications addObject:notificationToSchedule];
  238. }
  239. }] scheduleLocalNotification:[OCMArg checkWithBlock:^BOOL(id obj) {
  240. if ([obj isKindOfClass:[UILocalNotification class]]) {
  241. notificationToSchedule = obj;
  242. return YES;
  243. }
  244. return NO;
  245. }]];
  246. #pragma clang diagnostic pop
  247. #endif // TARGET_OS_IOS
  248. }
  249. - (void)testScheduleiOS10LocalNotification {
  250. if (@available(macOS 10.14, *)) {
  251. id mockContextManagerService = OCMClassMock([FIRMessagingContextManagerService class]);
  252. NSDictionary *message = @{};
  253. [FIRMessagingContextManagerService scheduleiOS10LocalNotificationForMessage:message
  254. atDate:[NSDate date]];
  255. OCMVerify([mockContextManagerService contentFromContextualMessage:message]);
  256. [mockContextManagerService stopMocking];
  257. }
  258. }
  259. - (void)testContentFromConetxtualMessage {
  260. if (@available(macOS 10.14, *)) {
  261. NSDictionary *message = @{
  262. @"aps" : @{@"content-available" : @1},
  263. @"gcm.message_id" : @1623702615599207,
  264. @"gcm.n.e" : @1,
  265. @"gcm.notification.badge" : @1,
  266. @"gcm.notification.body" : kBody,
  267. @"gcm.notification.image" :
  268. @"https://firebasestorage.googleapis.com/v0/b/fir-ios-app-extensions.appspot.com/o/"
  269. @"sparkyWFH.png?alt=media&token=f4dc1533-4d80-4ed6-9870-8df528593157",
  270. @"gcm.notification.mutable_content" : @1,
  271. @"gcm.notification.sound" : kSoundName,
  272. @"gcm.notification.sound2" : kSoundName,
  273. @"gcm.notification.title" : kTitle,
  274. // This field is not popped out from console
  275. // Manual add here to test unit test
  276. @"gcm.notification.click_action" : kAction,
  277. @"gcms" : @"gcm.gmsproc.cm",
  278. @"google.c.a.c_id" : @2159728303499680621,
  279. @"google.c.a.c_l" : @"test local send with sound",
  280. @"google.c.a.e" : @1,
  281. @"google.c.a.ts" : @1623753000,
  282. @"google.c.a.udt" : @1,
  283. @"google.c.cm.lt_end" : @"2021-07-13 10:30:00",
  284. @"google.c.cm.lt_start" : @"2021-06-15 10:30:00",
  285. @"google.c.sender.id" : @449451107265,
  286. };
  287. UNMutableNotificationContent *content =
  288. [FIRMessagingContextManagerService contentFromContextualMessage:message];
  289. XCTAssertEqualObjects(content.badge, @1);
  290. #if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
  291. XCTAssertEqualObjects(content.body, kBody);
  292. XCTAssertEqualObjects(content.title, kTitle);
  293. #if !TARGET_OS_WATCH
  294. XCTAssertEqualObjects(content.sound, [UNNotificationSound soundNamed:kSoundName]);
  295. #else // !TARGET_OS_WATCH
  296. XCTAssertEqualObjects(content.sound, [UNNotificationSound defaultSound]);
  297. #endif // !TARGET_OS_WATCH
  298. XCTAssertEqualObjects(content.categoryIdentifier, kAction);
  299. NSDictionary *userInfo = @{
  300. @"gcm.message_id" : @1623702615599207,
  301. @"gcm.n.e" : @1,
  302. @"gcm.notification.badge" : @1,
  303. @"gcm.notification.body" : kBody,
  304. @"gcm.notification.image" :
  305. @"https://firebasestorage.googleapis.com/v0/b/fir-ios-app-extensions.appspot.com/o/"
  306. @"sparkyWFH.png?alt=media&token=f4dc1533-4d80-4ed6-9870-8df528593157",
  307. @"gcm.notification.mutable_content" : @1,
  308. @"gcm.notification.sound" : kSoundName,
  309. @"gcm.notification.sound2" : kSoundName,
  310. @"gcm.notification.title" : kTitle,
  311. // This field is not popped out from console
  312. // Manual add here to test unit test
  313. @"gcm.notification.click_action" : kAction,
  314. @"gcms" : @"gcm.gmsproc.cm",
  315. @"google.c.a.c_id" : @2159728303499680621,
  316. @"google.c.a.c_l" : @"test local send with sound",
  317. @"google.c.a.e" : @1,
  318. @"google.c.a.ts" : @1623753000,
  319. @"google.c.a.udt" : @1,
  320. @"google.c.sender.id" : @449451107265
  321. };
  322. XCTAssertEqualObjects(content.userInfo, userInfo);
  323. #endif // TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
  324. }
  325. }
  326. @end