FIRMessagingAnalyticsTest.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. * Copyright 2018 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 <XCTest/XCTest.h>
  18. #import "FIRMessagingAnalytics.h"
  19. #import <FirebaseAnalyticsInterop/FIRInteropEventNames.h>
  20. #import <FirebaseAnalyticsInterop/FIRInteropParameterNames.h>
  21. static NSString *const kFIRParameterLabel = @"label";
  22. static NSString *const kReengagementSource = @"Firebase";
  23. static NSString *const kReengagementMedium = @"notification";
  24. static NSString *const kFIREventOriginFCM = @"fcm";
  25. static const NSTimeInterval kAsyncTestTimout = 0.5;
  26. typedef void (^FakeAnalyticsLogEventHandler)(NSString *origin,
  27. NSString *name,
  28. NSDictionary *parameters);
  29. typedef void (^FakeAnalyticsUserPropertyHandler)(NSString *origin,
  30. NSString *name,
  31. id value);
  32. @interface FakeAnalytics : NSObject <FIRAnalyticsInterop>
  33. - (instancetype)initWithEventHandler:(FakeAnalyticsLogEventHandler)eventHandler;
  34. - (instancetype)initWithUserPropertyHandler:(FakeAnalyticsUserPropertyHandler)userPropertyHandler;
  35. @end
  36. @implementation FakeAnalytics
  37. static FakeAnalyticsLogEventHandler _eventHandler;
  38. static FakeAnalyticsLogEventHandler _userPropertyHandler;
  39. - (instancetype)initWithEventHandler:(FakeAnalyticsLogEventHandler)eventHandler {
  40. self = [super init];
  41. if (self) {
  42. _eventHandler = eventHandler;
  43. }
  44. return self;
  45. }
  46. - (instancetype)initWithUserPropertyHandler:(FakeAnalyticsUserPropertyHandler)userPropertyHandler {
  47. self = [super init];
  48. if (self) {
  49. _userPropertyHandler = userPropertyHandler;
  50. }
  51. return self;
  52. }
  53. - (void)logEventWithOrigin:(nonnull NSString *)origin
  54. name:(nonnull NSString *)name
  55. parameters:(nullable NSDictionary<NSString *, id> *)parameters {
  56. if (_eventHandler) {
  57. _eventHandler(origin, name, parameters);
  58. }
  59. }
  60. - (void)setUserPropertyWithOrigin:(nonnull NSString *)origin
  61. name:(nonnull NSString *)name
  62. value:(nonnull id)value {
  63. if (_userPropertyHandler) {
  64. _userPropertyHandler(origin, name, value);
  65. }
  66. }
  67. // Stubs
  68. - (void)clearConditionalUserProperty:(nonnull NSString *)userPropertyName
  69. clearEventName:(nonnull NSString *)clearEventName
  70. clearEventParameters:(nonnull NSDictionary *)clearEventParameters {
  71. }
  72. - (nonnull NSArray<FIRAConditionalUserProperty *> *)
  73. conditionalUserProperties:(nonnull NSString *)origin
  74. propertyNamePrefix:(nonnull NSString *)propertyNamePrefix {
  75. return @[];
  76. }
  77. - (NSInteger)maxUserProperties:(nonnull NSString *)origin {
  78. return -1;
  79. }
  80. - (void)setConditionalUserProperty:(nonnull FIRAConditionalUserProperty *)conditionalUserProperty {
  81. }
  82. - (void)checkLastNotificationForOrigin:(nonnull NSString *)origin
  83. queue:(nonnull dispatch_queue_t)queue
  84. callback:(nonnull void (^)(NSString *_Nullable))
  85. currentLastNotificationProperty {
  86. }
  87. - (void)registerAnalyticsListener:(nonnull id<FIRAnalyticsInteropListener>)listener
  88. withOrigin:(nonnull NSString *)origin {
  89. }
  90. - (void)unregisterAnalyticsListenerWithOrigin:(nonnull NSString *)origin {
  91. }
  92. @end
  93. @interface FIRMessagingAnalytics (ExposedForTest)
  94. + (BOOL)canLogNotification:(NSDictionary *)notification;
  95. + (NSMutableDictionary *)paramsForEvent:(NSString *)event
  96. withNotification:(NSDictionary *)notification;
  97. + (void)logAnalyticsEventWithOrigin:(NSString *)origin
  98. name:(NSString *)name
  99. parameters:(NSDictionary *)params
  100. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics;
  101. + (void)logUserPropertyForConversionTracking:(NSDictionary *)notification
  102. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics;
  103. + (void)logOpenNotification:(NSDictionary *)notification
  104. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics;
  105. + (void)logForegroundNotification:(NSDictionary *)notification
  106. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics;
  107. + (void)logEvent:(NSString *)event
  108. withNotification:(NSDictionary *)notification
  109. toAnalytics:(id<FIRAnalyticsInterop> _Nullable)analytics ;;
  110. @end
  111. @interface FIRMessagingAnalyticsTest : XCTestCase
  112. @property(nonatomic, readwrite, strong) id logClassMock;
  113. @end
  114. @implementation FIRMessagingAnalyticsTest
  115. - (void)setUp {
  116. [super setUp];
  117. self.logClassMock = OCMClassMock([FIRMessagingAnalytics class]);
  118. }
  119. - (void)tearDown {
  120. _eventHandler = nil;
  121. _userPropertyHandler = nil;
  122. [self.logClassMock stopMocking];
  123. [super tearDown];
  124. }
  125. - (void)testCanLogNotification {
  126. NSDictionary *notification = @{};
  127. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  128. notification = @{@"google.c.a.e" : @1};
  129. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  130. notification = @{@"aps" : @{@"alert" : @"to check the reporting format"}};
  131. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  132. notification = @{@"aps" : @{@"alert" : @"to check the reporting format"}, @"google.c.a.e" : @"0"};
  133. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  134. notification = @{
  135. @"aps" : @{@"alert" : @"to check the reporting format"},
  136. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  137. @"gcm.n.e" : @"1",
  138. @"google.c.a.c_id" : @"575315420755741863",
  139. @"google.c.a.e" : @"1",
  140. @"google.c.a.ts" : @"1522880044",
  141. @"google.c.a.udt" : @"0"
  142. };
  143. XCTAssertTrue([FIRMessagingAnalytics canLogNotification:notification]);
  144. notification = @{
  145. @"aps" : @{@"content-available" : @"1"},
  146. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  147. @"google.c.a.e" : @"1",
  148. @"google.c.a.ts" : @"1522880044",
  149. @"google.c.a.udt" : @"0"
  150. };
  151. XCTAssertTrue([FIRMessagingAnalytics canLogNotification:notification]);
  152. }
  153. - (void)testEmptyNotification {
  154. NSMutableDictionary *params = [FIRMessagingAnalytics paramsForEvent:@"" withNotification:@{}];
  155. XCTAssertNil(params);
  156. }
  157. - (void)testNoParamsIfAnalyticsIsNotEnabled {
  158. NSDictionary *notification = @{
  159. @"aps" : @{@"alert" : @"to check the reporting format"},
  160. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  161. @"gcm.n.e" : @"1",
  162. @"google.c.a.c_id" : @"575315420755741863",
  163. @"google.c.a.ts" : @"1522880044",
  164. @"google.c.a.udt" : @"0"
  165. };
  166. NSMutableDictionary *params = [FIRMessagingAnalytics paramsForEvent:@"" withNotification:notification];
  167. XCTAssertNil(params);
  168. }
  169. - (void)testNoParamsIfEmpty {
  170. NSDictionary *notification = @{
  171. @"google.c.a.e" : @"1",
  172. };
  173. NSMutableDictionary *params = [FIRMessagingAnalytics paramsForEvent:@""
  174. withNotification:notification];
  175. XCTAssertNotNil(params);
  176. XCTestExpectation *expectation = [self expectationWithDescription:@"completion"];
  177. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  178. initWithEventHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) {
  179. XCTAssertEqualObjects(origin, kFIREventOriginFCM);
  180. XCTAssertEqualObjects(name, @"_cmp");
  181. XCTAssertEqual([parameters count], 0);
  182. [expectation fulfill];
  183. }];
  184. [FIRMessagingAnalytics logEvent:kFIRIEventFirebaseCampaign
  185. withNotification:notification
  186. toAnalytics:analytics];
  187. [self waitForExpectationsWithTimeout:kAsyncTestTimout handler:nil];
  188. }
  189. - (void)testParamForEventAndNotification {
  190. NSDictionary *notification = @{
  191. @"aps" : @{@"alert" : @"to check the reporting format"},
  192. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  193. @"gcm.n.e" : @"1",
  194. @"google.c.a.c_l" : @"Hello World",
  195. @"google.c.a.c_id" : @"575315420755741863",
  196. @"google.c.a.e" : @"1",
  197. @"google.c.a.ts" : @"1522880044",
  198. @"google.c.a.udt" : @"0",
  199. @"google.c.a.m_l" : @"developer's customized label",
  200. @"from" : @"/topics/news",
  201. };
  202. NSMutableDictionary *params =
  203. [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  204. XCTAssertNotNil(params);
  205. XCTAssertEqualObjects(params[kFIRIParameterMessageIdentifier], @"575315420755741863");
  206. XCTAssertEqualObjects(params[kFIRIParameterMessageName], @"Hello World");
  207. XCTAssertEqualObjects(params[kFIRParameterLabel], @"developer's customized label");
  208. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  209. XCTAssertEqualObjects([params[kFIRIParameterMessageTime] stringValue], @"1522880044");
  210. XCTAssertEqualObjects(params[kFIRIParameterMessageDeviceTime], @"0");
  211. }
  212. - (void)testInvalidDataInParamsForLogging {
  213. NSString *composerIdentifier = @"Hellow World";
  214. NSDictionary *notification = @{
  215. @"google.c.a.e" : @(YES),
  216. @"google.c.a.c_l" : composerIdentifier,
  217. @"google.c.a.c_id" : @"575315420755741863",
  218. @"google.c.a.m_l" : @"developer's customized label",
  219. @"google.c.a.ts" : @"1522880044",
  220. @"from" : @"/topics/news",
  221. @"google.c.a.udt" : @"0",
  222. };
  223. NSMutableDictionary *params =
  224. [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  225. XCTAssertNil(params);
  226. notification = @{
  227. @"google.c.a.e" : @"1",
  228. @"google.c.a.c_l" : [composerIdentifier dataUsingEncoding:NSUTF8StringEncoding],
  229. @"google.c.a.c_id" : @"575315420755741863",
  230. @"google.c.a.m_l" : @"developer's customized label",
  231. @"google.c.a.ts" : @"1522880044",
  232. @"from" : @"/topics/news",
  233. @"google.c.a.udt" : @"0",
  234. };
  235. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  236. XCTAssertNil(params[kFIRIParameterMessageName]);
  237. XCTAssertEqualObjects(params[kFIRIParameterMessageIdentifier], @"575315420755741863");
  238. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  239. notification = @{
  240. @"google.c.a.e" : @"1",
  241. @"google.c.a.c_l" : composerIdentifier,
  242. @"google.c.a.c_id" : @(575315420755741863),
  243. @"google.c.a.m_l" : @"developer's customized label",
  244. @"google.c.a.ts" : @"1522880044",
  245. @"from" : @"/topics/news",
  246. @"google.c.a.udt" : @"0",
  247. };
  248. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  249. XCTAssertEqualObjects(params[kFIRIParameterMessageName], composerIdentifier);
  250. XCTAssertNil(params[kFIRIParameterMessageIdentifier]);
  251. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  252. notification = @{
  253. @"google.c.a.e" : @"1",
  254. @"google.c.a.c_l" : composerIdentifier,
  255. @"google.c.a.c_id" : @"575315420755741863",
  256. @"google.c.a.m_l" : @"developer's customized label",
  257. @"google.c.a.ts" : @"0",
  258. @"from" : @"/topics/news",
  259. @"google.c.a.udt" : @"12345678",
  260. };
  261. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  262. XCTAssertEqualObjects(params[kFIRIParameterMessageName], composerIdentifier);
  263. XCTAssertEqualObjects(params[kFIRIParameterMessageIdentifier], @"575315420755741863");
  264. XCTAssertEqualObjects(params[kFIRParameterLabel], @"developer's customized label");
  265. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  266. XCTAssertNil(params[kFIRIParameterMessageTime]);
  267. XCTAssertEqualObjects(params[kFIRIParameterMessageDeviceTime], @"12345678");
  268. notification = @{
  269. @"google.c.a.e" : @"1",
  270. @"google.c.a.c_l" : composerIdentifier,
  271. @"google.c.a.c_id" : @"575315420755741863",
  272. @"google.c.a.m_l" : @"developer's customized label",
  273. @"google.c.a.ts" : @(0),
  274. @"from" : @"/topics/news",
  275. @"google.c.a.udt" : @"12345678",
  276. };
  277. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  278. XCTAssertEqualObjects(params[kFIRIParameterMessageName], composerIdentifier);
  279. XCTAssertNil(params[kFIRIParameterMessageTime]);
  280. XCTAssertEqualObjects(params[kFIRIParameterMessageDeviceTime], @"12345678");
  281. }
  282. - (void)testConversionTracking {
  283. // Notification contains "google.c.a.tc" key.
  284. NSDictionary *notification = @{
  285. @"aps" : @{@"alert" : @"to check the reporting format"},
  286. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  287. @"gcm.n.e" : @"1",
  288. @"google.c.a.c_l" : @"Hello World",
  289. @"google.c.a.c_id" : @"575315420755741863",
  290. @"google.c.a.e" : @"1",
  291. @"google.c.a.ts" : @"1522880044",
  292. @"google.c.a.udt" : @"0",
  293. @"google.c.a.m_l" : @"developer's customized label",
  294. @"google.c.a.tc" : @"1",
  295. @"from" : @"/topics/news",
  296. };
  297. NSDictionary *params = @{
  298. kFIRIParameterSource : kReengagementSource,
  299. kFIRIParameterMedium : kReengagementMedium,
  300. kFIRIParameterCampaign : @"575315420755741863"
  301. };
  302. __block XCTestExpectation *expectation = [self expectationWithDescription:@"completion"];
  303. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  304. initWithEventHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) {
  305. XCTAssertEqualObjects(origin, kFIREventOriginFCM);
  306. XCTAssertEqualObjects(name, @"_cmp");
  307. XCTAssertEqualObjects(parameters, params);
  308. [expectation fulfill];
  309. expectation = nil;
  310. }];
  311. [FIRMessagingAnalytics logUserPropertyForConversionTracking:notification toAnalytics:analytics];
  312. [self waitForExpectationsWithTimeout:kAsyncTestTimout handler:nil];
  313. }
  314. - (void)testConversionTrackingUserProperty {
  315. // Notification contains "google.c.a.tc" key.
  316. NSDictionary *notification = @{
  317. @"aps" : @{@"alert" : @"to check the reporting format"},
  318. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  319. @"gcm.n.e" : @"1",
  320. @"google.c.a.c_l" : @"Hello World",
  321. @"google.c.a.c_id" : @"575315420755741863",
  322. @"google.c.a.e" : @"1",
  323. @"google.c.a.ts" : @"1522880044",
  324. @"google.c.a.udt" : @"0",
  325. @"google.c.a.m_l" : @"developer's customized label",
  326. @"google.c.a.tc" : @"1",
  327. @"from" : @"/topics/news",
  328. };
  329. XCTestExpectation *expectation = [self expectationWithDescription:@"completion"];
  330. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  331. initWithUserPropertyHandler:^(NSString *origin, NSString *name, id value) {
  332. XCTAssertEqualObjects(origin, kFIREventOriginFCM);
  333. XCTAssertEqualObjects(name, @"_ln");
  334. XCTAssertEqualObjects(value, @"575315420755741863");
  335. [expectation fulfill];
  336. }];
  337. [FIRMessagingAnalytics logUserPropertyForConversionTracking:notification toAnalytics:analytics];
  338. [self waitForExpectationsWithTimeout:kAsyncTestTimout handler:nil];
  339. }
  340. - (void)testNoConversionTracking {
  341. // Notification contains "google.c.a.tc" key.
  342. NSDictionary *notification = @{
  343. @"aps" : @{@"alert" : @"to check the reporting format"},
  344. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  345. @"gcm.n.e" : @"1",
  346. @"google.c.a.c_l" : @"Hello World",
  347. @"google.c.a.c_id" : @"575315420755741863",
  348. @"google.c.a.e" : @"1",
  349. @"google.c.a.ts" : @"1522880044",
  350. @"google.c.a.udt" : @"0",
  351. @"google.c.a.m_l" : @"developer's customized label",
  352. @"from" : @"/topics/news",
  353. };
  354. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  355. initWithEventHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) {
  356. XCTAssertTrue(NO);
  357. }];
  358. [FIRMessagingAnalytics logUserPropertyForConversionTracking:notification toAnalytics:analytics];
  359. }
  360. - (void)testLogMessage {
  361. NSDictionary *notification = @{
  362. @"google.c.a.e" : @"1",
  363. };
  364. [FIRMessagingAnalytics logMessage:notification toAnalytics:nil];
  365. OCMVerify([self.logClassMock logEvent:OCMOCK_ANY withNotification:notification toAnalytics:nil]);
  366. }
  367. - (void)testLogOpenNotification {
  368. NSDictionary *notification = @{
  369. @"google.c.a.e" : @"1",
  370. };
  371. [FIRMessagingAnalytics logOpenNotification:notification toAnalytics:nil];
  372. OCMVerify([self.logClassMock logUserPropertyForConversionTracking:notification toAnalytics:nil]);
  373. OCMVerify([self.logClassMock logEvent:kFIRIEventNotificationOpen
  374. withNotification:notification
  375. toAnalytics:nil]);
  376. }
  377. @end