FIRMessagingAnalyticsTest.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  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. [self.logClassMock stopMocking];
  121. [super tearDown];
  122. }
  123. - (void)testCanLogNotification {
  124. NSDictionary *notification = @{};
  125. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  126. notification = @{@"google.c.a.e" : @1};
  127. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  128. notification = @{@"aps" : @{@"alert" : @"to check the reporting format"}};
  129. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  130. notification = @{@"aps" : @{@"alert" : @"to check the reporting format"}, @"google.c.a.e" : @"0"};
  131. XCTAssertFalse([FIRMessagingAnalytics canLogNotification:notification]);
  132. notification = @{
  133. @"aps" : @{@"alert" : @"to check the reporting format"},
  134. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  135. @"gcm.n.e" : @"1",
  136. @"google.c.a.c_id" : @"575315420755741863",
  137. @"google.c.a.e" : @"1",
  138. @"google.c.a.ts" : @"1522880044",
  139. @"google.c.a.udt" : @"0"
  140. };
  141. XCTAssertTrue([FIRMessagingAnalytics canLogNotification:notification]);
  142. notification = @{
  143. @"aps" : @{@"content-available" : @"1"},
  144. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  145. @"google.c.a.e" : @"1",
  146. @"google.c.a.ts" : @"1522880044",
  147. @"google.c.a.udt" : @"0"
  148. };
  149. XCTAssertTrue([FIRMessagingAnalytics canLogNotification:notification]);
  150. }
  151. - (void)testEmptyNotification {
  152. NSMutableDictionary *params = [FIRMessagingAnalytics paramsForEvent:@"" withNotification:@{}];
  153. XCTAssertNil(params);
  154. }
  155. - (void)testNoParamsIfAnalyticsIsNotEnabled {
  156. NSDictionary *notification = @{
  157. @"aps" : @{@"alert" : @"to check the reporting format"},
  158. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  159. @"gcm.n.e" : @"1",
  160. @"google.c.a.c_id" : @"575315420755741863",
  161. @"google.c.a.ts" : @"1522880044",
  162. @"google.c.a.udt" : @"0"
  163. };
  164. NSMutableDictionary *params = [FIRMessagingAnalytics paramsForEvent:@"" withNotification:notification];
  165. XCTAssertNil(params);
  166. }
  167. - (void)testNoParamsIfEmpty {
  168. NSDictionary *notification = @{
  169. @"google.c.a.e" : @"1",
  170. };
  171. NSMutableDictionary *params = [FIRMessagingAnalytics paramsForEvent:@""
  172. withNotification:notification];
  173. XCTAssertNotNil(params);
  174. XCTestExpectation *expectation = [self expectationWithDescription:@"completion"];
  175. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  176. initWithEventHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) {
  177. XCTAssertEqualObjects(origin, kFIREventOriginFCM);
  178. XCTAssertEqualObjects(name, @"_cmp");
  179. XCTAssertEqual([parameters count], 0);
  180. [expectation fulfill];
  181. }];
  182. [FIRMessagingAnalytics logEvent:kFIRIEventFirebaseCampaign
  183. withNotification:notification
  184. toAnalytics:analytics];
  185. [self waitForExpectationsWithTimeout:kAsyncTestTimout handler:nil];
  186. }
  187. - (void)testParamForEventAndNotification {
  188. NSDictionary *notification = @{
  189. @"aps" : @{@"alert" : @"to check the reporting format"},
  190. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  191. @"gcm.n.e" : @"1",
  192. @"google.c.a.c_l" : @"Hello World",
  193. @"google.c.a.c_id" : @"575315420755741863",
  194. @"google.c.a.e" : @"1",
  195. @"google.c.a.ts" : @"1522880044",
  196. @"google.c.a.udt" : @"0",
  197. @"google.c.a.m_l" : @"developer's customized label",
  198. @"from" : @"/topics/news",
  199. };
  200. NSMutableDictionary *params =
  201. [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  202. XCTAssertNotNil(params);
  203. XCTAssertEqualObjects(params[kFIRIParameterMessageIdentifier], @"575315420755741863");
  204. XCTAssertEqualObjects(params[kFIRIParameterMessageName], @"Hello World");
  205. XCTAssertEqualObjects(params[kFIRParameterLabel], @"developer's customized label");
  206. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  207. XCTAssertEqualObjects([params[kFIRIParameterMessageTime] stringValue], @"1522880044");
  208. XCTAssertEqualObjects(params[kFIRIParameterMessageDeviceTime], @"0");
  209. }
  210. - (void)testInvalidDataInParamsForLogging {
  211. NSString *composerIdentifier = @"Hellow World";
  212. NSDictionary *notification = @{
  213. @"google.c.a.e" : @(YES),
  214. @"google.c.a.c_l" : composerIdentifier,
  215. @"google.c.a.c_id" : @"575315420755741863",
  216. @"google.c.a.m_l" : @"developer's customized label",
  217. @"google.c.a.ts" : @"1522880044",
  218. @"from" : @"/topics/news",
  219. @"google.c.a.udt" : @"0",
  220. };
  221. NSMutableDictionary *params =
  222. [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  223. XCTAssertNil(params);
  224. notification = @{
  225. @"google.c.a.e" : @"1",
  226. @"google.c.a.c_l" : [composerIdentifier dataUsingEncoding:NSUTF8StringEncoding],
  227. @"google.c.a.c_id" : @"575315420755741863",
  228. @"google.c.a.m_l" : @"developer's customized label",
  229. @"google.c.a.ts" : @"1522880044",
  230. @"from" : @"/topics/news",
  231. @"google.c.a.udt" : @"0",
  232. };
  233. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  234. XCTAssertNil(params[kFIRIParameterMessageName]);
  235. XCTAssertEqualObjects(params[kFIRIParameterMessageIdentifier], @"575315420755741863");
  236. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  237. notification = @{
  238. @"google.c.a.e" : @"1",
  239. @"google.c.a.c_l" : composerIdentifier,
  240. @"google.c.a.c_id" : @(575315420755741863),
  241. @"google.c.a.m_l" : @"developer's customized label",
  242. @"google.c.a.ts" : @"1522880044",
  243. @"from" : @"/topics/news",
  244. @"google.c.a.udt" : @"0",
  245. };
  246. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  247. XCTAssertEqualObjects(params[kFIRIParameterMessageName], composerIdentifier);
  248. XCTAssertNil(params[kFIRIParameterMessageIdentifier]);
  249. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  250. notification = @{
  251. @"google.c.a.e" : @"1",
  252. @"google.c.a.c_l" : composerIdentifier,
  253. @"google.c.a.c_id" : @"575315420755741863",
  254. @"google.c.a.m_l" : @"developer's customized label",
  255. @"google.c.a.ts" : @"0",
  256. @"from" : @"/topics/news",
  257. @"google.c.a.udt" : @"12345678",
  258. };
  259. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  260. XCTAssertEqualObjects(params[kFIRIParameterMessageName], composerIdentifier);
  261. XCTAssertEqualObjects(params[kFIRIParameterMessageIdentifier], @"575315420755741863");
  262. XCTAssertEqualObjects(params[kFIRParameterLabel], @"developer's customized label");
  263. XCTAssertEqualObjects(params[kFIRIParameterTopic], @"/topics/news");
  264. XCTAssertNil(params[kFIRIParameterMessageTime]);
  265. XCTAssertEqualObjects(params[kFIRIParameterMessageDeviceTime], @"12345678");
  266. notification = @{
  267. @"google.c.a.e" : @"1",
  268. @"google.c.a.c_l" : composerIdentifier,
  269. @"google.c.a.c_id" : @"575315420755741863",
  270. @"google.c.a.m_l" : @"developer's customized label",
  271. @"google.c.a.ts" : @(0),
  272. @"from" : @"/topics/news",
  273. @"google.c.a.udt" : @"12345678",
  274. };
  275. params = [FIRMessagingAnalytics paramsForEvent:kFIRIEventNotificationOpen withNotification:notification];
  276. XCTAssertEqualObjects(params[kFIRIParameterMessageName], composerIdentifier);
  277. XCTAssertNil(params[kFIRIParameterMessageTime]);
  278. XCTAssertEqualObjects(params[kFIRIParameterMessageDeviceTime], @"12345678");
  279. }
  280. - (void)testConversionTracking {
  281. // Notification contains "google.c.a.tc" key.
  282. NSDictionary *notification = @{
  283. @"aps" : @{@"alert" : @"to check the reporting format"},
  284. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  285. @"gcm.n.e" : @"1",
  286. @"google.c.a.c_l" : @"Hello World",
  287. @"google.c.a.c_id" : @"575315420755741863",
  288. @"google.c.a.e" : @"1",
  289. @"google.c.a.ts" : @"1522880044",
  290. @"google.c.a.udt" : @"0",
  291. @"google.c.a.m_l" : @"developer's customized label",
  292. @"google.c.a.tc" : @"1",
  293. @"from" : @"/topics/news",
  294. };
  295. NSDictionary *params = @{
  296. kFIRIParameterSource : kReengagementSource,
  297. kFIRIParameterMedium : kReengagementMedium,
  298. kFIRIParameterCampaign : @"575315420755741863"
  299. };
  300. __block XCTestExpectation *expectation = [self expectationWithDescription:@"completion"];
  301. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  302. initWithEventHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) {
  303. XCTAssertEqualObjects(origin, kFIREventOriginFCM);
  304. XCTAssertEqualObjects(name, @"_cmp");
  305. XCTAssertEqualObjects(parameters, params);
  306. [expectation fulfill];
  307. expectation = nil;
  308. }];
  309. [FIRMessagingAnalytics logUserPropertyForConversionTracking:notification toAnalytics:analytics];
  310. [self waitForExpectationsWithTimeout:kAsyncTestTimout handler:nil];
  311. }
  312. - (void)testConversionTrackingUserProperty {
  313. // Notification contains "google.c.a.tc" key.
  314. NSDictionary *notification = @{
  315. @"aps" : @{@"alert" : @"to check the reporting format"},
  316. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  317. @"gcm.n.e" : @"1",
  318. @"google.c.a.c_l" : @"Hello World",
  319. @"google.c.a.c_id" : @"575315420755741863",
  320. @"google.c.a.e" : @"1",
  321. @"google.c.a.ts" : @"1522880044",
  322. @"google.c.a.udt" : @"0",
  323. @"google.c.a.m_l" : @"developer's customized label",
  324. @"google.c.a.tc" : @"1",
  325. @"from" : @"/topics/news",
  326. };
  327. XCTestExpectation *expectation = [self expectationWithDescription:@"completion"];
  328. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  329. initWithUserPropertyHandler:^(NSString *origin, NSString *name, id value) {
  330. XCTAssertEqualObjects(origin, kFIREventOriginFCM);
  331. XCTAssertEqualObjects(name, @"_ln");
  332. XCTAssertEqualObjects(value, @"575315420755741863");
  333. [expectation fulfill];
  334. }];
  335. [FIRMessagingAnalytics logUserPropertyForConversionTracking:notification toAnalytics:analytics];
  336. [self waitForExpectationsWithTimeout:kAsyncTestTimout handler:nil];
  337. }
  338. - (void)testNoConversionTracking {
  339. // Notification contains "google.c.a.tc" key.
  340. NSDictionary *notification = @{
  341. @"aps" : @{@"alert" : @"to check the reporting format"},
  342. @"gcm.message_id" : @"0:1522880049414338%944841cd944841cd",
  343. @"gcm.n.e" : @"1",
  344. @"google.c.a.c_l" : @"Hello World",
  345. @"google.c.a.c_id" : @"575315420755741863",
  346. @"google.c.a.e" : @"1",
  347. @"google.c.a.ts" : @"1522880044",
  348. @"google.c.a.udt" : @"0",
  349. @"google.c.a.m_l" : @"developer's customized label",
  350. @"from" : @"/topics/news",
  351. };
  352. FakeAnalytics *analytics = [[FakeAnalytics alloc]
  353. initWithEventHandler:^(NSString *origin, NSString *name, NSDictionary *parameters) {
  354. XCTAssertTrue(NO);
  355. }];
  356. [FIRMessagingAnalytics logUserPropertyForConversionTracking:notification toAnalytics:analytics];
  357. }
  358. - (void)testLogMessage {
  359. NSDictionary *notification = @{
  360. @"google.c.a.e" : @"1",
  361. };
  362. [FIRMessagingAnalytics logMessage:notification toAnalytics:nil];
  363. OCMVerify([self.logClassMock logEvent:OCMOCK_ANY withNotification:notification toAnalytics:nil]);
  364. }
  365. - (void)testLogOpenNotification {
  366. NSDictionary *notification = @{
  367. @"google.c.a.e" : @"1",
  368. };
  369. [FIRMessagingAnalytics logOpenNotification:notification toAnalytics:nil];
  370. OCMVerify([self.logClassMock logUserPropertyForConversionTracking:notification toAnalytics:nil]);
  371. OCMVerify([self.logClassMock logEvent:kFIRIEventNotificationOpen
  372. withNotification:notification
  373. toAnalytics:nil]);
  374. }
  375. @end