FIRMessagingContextManagerServiceTest.m 14 KB

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