FPRGDTCCLoggerTest.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import <XCTest/XCTest.h>
  15. #import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h"
  16. #import "FirebasePerformance/Sources/Loggers/FPRGDTCCLogger.h"
  17. #import "FirebasePerformance/Sources/Loggers/FPRGDTCCLogger_Private.h"
  18. #import "FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h"
  19. #import "FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h"
  20. #import "FirebasePerformance/Tests/Unit/Configurations/FPRFakeRemoteConfig.h"
  21. #import "FirebasePerformance/Tests/Unit/Configurations/FPRFakeRemoteConfigFlags.h"
  22. #import "FirebasePerformance/Tests/Unit/Fakes/FPRFakeConfigurations.h"
  23. #import "FirebasePerformance/Tests/Unit/FPRTestUtils.h"
  24. #import <GoogleDataTransport/GoogleDataTransport.h>
  25. #import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h"
  26. #import "GoogleDataTransport/GDTCORTests/Common/Fakes/GDTCORTransportFake.h"
  27. #import "FirebasePerformance/ProtoSupport/PerfMetric.pbobjc.h"
  28. @interface FPRGDTCCLoggerTest : XCTestCase
  29. /** Clearcut logger used to dispatch events to Clearcut using Google Data Transport. */
  30. @property(nonatomic) FPRGDTCCLogger *logger;
  31. /** A fake for the GDTCORTransport for clearcut. */
  32. @property(nonatomic) GDTCORTransportFake *transportCCTFake;
  33. /** A fake for the GDTCORTransport for FLL. */
  34. @property(nonatomic) GDTCORTransportFake *transportFLLFake;
  35. /** The log source for the FPRGDTCCLogger to be used. */
  36. @property(nonatomic) NSInteger logSource;
  37. /** The target backend of the GDTCORTransport - Clearcut. */
  38. @property(nonatomic) NSInteger targetCCT;
  39. /** The target backend of the GDTCORTransport - FLL. */
  40. @property(nonatomic) NSInteger targetFL;
  41. @end
  42. @implementation FPRGDTCCLoggerTest
  43. - (void)setUp {
  44. [super setUp];
  45. self.logSource = 1;
  46. self.targetCCT = kGDTCORTargetCCT; // CCT
  47. self.targetFL = kGDTCORTargetFLL; // FLL
  48. self.logger = [[FPRGDTCCLogger alloc] initWithLogSource:self.logSource];
  49. self.logger.isSimulator = YES;
  50. // Set up for Fake logging.
  51. self.transportCCTFake =
  52. [[GDTCORTransportFake alloc] initWithMappingID:@(self.logSource).stringValue
  53. transformers:nil
  54. target:self.targetCCT];
  55. self.transportFLLFake =
  56. [[GDTCORTransportFake alloc] initWithMappingID:@(self.logSource).stringValue
  57. transformers:nil
  58. target:self.targetFL];
  59. self.logger.gdtcctTransport = self.transportCCTFake;
  60. self.logger.gdtfllTransport = self.transportFLLFake;
  61. }
  62. - (void)tearDown {
  63. [self.transportCCTFake reset];
  64. [self.transportFLLFake reset];
  65. [super tearDown];
  66. }
  67. /** Tests the designated initializer. */
  68. - (void)testInitWithLogSource {
  69. NSInteger randomLogSource = 1;
  70. FPRGDTCCLogger *logger = [[FPRGDTCCLogger alloc] initWithLogSource:randomLogSource];
  71. XCTAssertNotNil(logger);
  72. XCTAssertEqual(logger.logSource, randomLogSource);
  73. XCTAssertNotNil(logger.gdtcctTransport);
  74. }
  75. /** Tests the GDTCCLogger is generated with designated transformers. */
  76. - (void)testInitWithTransformers {
  77. NSInteger randomLogSource = 1;
  78. FPRGDTCCLogger *logger = [[FPRGDTCCLogger alloc] initWithLogSource:randomLogSource];
  79. XCTAssertNotNil(logger);
  80. XCTAssertNotNil(logger.gdtcctTransport);
  81. XCTAssertNotNil(logger.gdtfllTransport);
  82. // Clearcut logger tests
  83. XCTAssertEqual(logger.gdtcctTransport.transformers.count, 2);
  84. XCTAssertTrue(
  85. [logger.gdtcctTransport.transformers.firstObject isKindOfClass:[FPRGDTLogSampler class]]);
  86. XCTAssertTrue(
  87. [logger.gdtcctTransport.transformers.lastObject isKindOfClass:[FPRGDTRateLimiter class]]);
  88. // GDT logger tests
  89. XCTAssertEqual(logger.gdtfllTransport.transformers.count, 2);
  90. XCTAssertTrue(
  91. [logger.gdtfllTransport.transformers.firstObject isKindOfClass:[FPRGDTLogSampler class]]);
  92. XCTAssertTrue(
  93. [logger.gdtfllTransport.transformers.lastObject isKindOfClass:[FPRGDTRateLimiter class]]);
  94. }
  95. /** Validate all the required fields are set when logging an Event. */
  96. - (void)testValidateEventFieldsToBeLogged {
  97. // Log the event.
  98. FPRMSGPerfMetric *event = [FPRTestUtils createRandomPerfMetric:@"t1"];
  99. event.applicationInfo.appInstanceId = @"abc";
  100. [self.logger logEvent:event];
  101. // Note: Refer "dispatch_async issue" in "testLogMultipleEvents".
  102. dispatch_sync(self.logger.queue, ^{
  103. // Fetch the logged event.
  104. NSArray<GDTCOREvent *> *gdtCorEventArray = [self.transportCCTFake logEvents];
  105. GDTCOREvent *gdtCorEvent = gdtCorEventArray.firstObject;
  106. // Validate that only 1 event is logged.
  107. XCTAssertEqual(gdtCorEventArray.count, 1);
  108. // Validate that the corresponding GDTEvent to be logged is not nil.
  109. XCTAssertNotNil(gdtCorEvent.dataObject);
  110. // Validate that the mapping ID is correctly associated.
  111. XCTAssertEqual(gdtCorEvent.mappingID, @(self.logSource).stringValue);
  112. // Validate that the target is correctly associated.
  113. XCTAssertEqual(gdtCorEvent.target, self.targetCCT);
  114. // Validate that the QoS is set to GDTCOREventQoSFast in debug mode.
  115. XCTAssertEqual(gdtCorEvent.qosTier, GDTCOREventQoSFast);
  116. });
  117. }
  118. /** Validate that multiple events are logged correctly. */
  119. - (void)testLogMultipleEvents {
  120. // Log the events.
  121. int logCount = 3;
  122. for (int i = 1; i <= logCount; i++) {
  123. NSString *traceName = [NSString stringWithFormat:@"t%d", i];
  124. FPRMSGPerfMetric *event = [FPRTestUtils createRandomPerfMetric:traceName];
  125. event.applicationInfo.appInstanceId = @"abc";
  126. [self.logger logEvent:event];
  127. }
  128. // Note: "dispatch_async issue"
  129. //
  130. // There's a race condition between we checking the logEvents property on the "transportFake"
  131. // and writing to that property using the "logEvent" method from the "logger" class
  132. // because we are dispatching that event in a "dispatch_async" queue.
  133. //
  134. // To mitigate this we want that block to finish executing, so we call "dispatch_sync"
  135. // on the same "queue" and perform all the validations inside that block.
  136. //
  137. // This is because it will block the current thread until all queued blocks are done.
  138. dispatch_sync(self.logger.queue, ^{
  139. // Fetch the logged events.
  140. NSArray<GDTCOREvent *> *gdtCorEventArray = [self.transportCCTFake logEvents];
  141. // Validate that the count of logged events is what is expected.
  142. XCTAssertEqual(gdtCorEventArray.count, logCount);
  143. });
  144. }
  145. /** Validate events' QoS are set to GDTCOREventQoSFast when running in Simulator. */
  146. - (void)testEventsSimulatorQoS {
  147. self.logger.isSimulator = YES;
  148. // Log the event.
  149. FPRMSGPerfMetric *event = [FPRTestUtils createRandomPerfMetric:@"t1"];
  150. event.applicationInfo.appInstanceId = @"abc";
  151. [self.logger logEvent:event];
  152. // Note: Refer "dispatch_async issue" in "testLogMultipleEvents".
  153. dispatch_sync(self.logger.queue, ^{
  154. // Fetch the logged event.
  155. NSArray<GDTCOREvent *> *gdtCorEventArray = [self.transportCCTFake logEvents];
  156. GDTCOREvent *gdtCorEvent = gdtCorEventArray.firstObject;
  157. // Validate that the QoS is set to GDTCOREventQoSFast.
  158. XCTAssertEqual(gdtCorEvent.qosTier, GDTCOREventQoSFast);
  159. });
  160. }
  161. /** Validate events' QoS are set to GDTCOREventQosDefault in actual device. */
  162. - (void)testEventsRealDeviceQoS {
  163. self.logger.isSimulator = NO;
  164. // Log the event.
  165. FPRMSGPerfMetric *event = [FPRTestUtils createRandomPerfMetric:@"t1"];
  166. event.applicationInfo.appInstanceId = @"abc";
  167. [self.logger logEvent:event];
  168. // Note: Refer "dispatch_async issue" in "testLogMultipleEvents".
  169. dispatch_sync(self.logger.queue, ^{
  170. // Fetch the logged event.
  171. NSArray<GDTCOREvent *> *gdtCorEventArray = [self.transportCCTFake logEvents];
  172. GDTCOREvent *gdtCorEvent = gdtCorEventArray.firstObject;
  173. // Validate that the QoS is set to GDTCOREventQosDefault.
  174. XCTAssertEqual(gdtCorEvent.qosTier, GDTCOREventQosDefault);
  175. });
  176. }
  177. /** Validate if the events are dispatched to FLL if installation ID seed is smaller than
  178. * transport percentage. */
  179. - (void)testEventDispatchedToFllWithInstallationIdSeedSeedSmallerThanTransportPercentage {
  180. self.logger.isSimulator = NO;
  181. // Initialize the configurations
  182. FPRFakeConfigurations *fakeConfigurations =
  183. [[FPRFakeConfigurations alloc] initWithSources:FPRConfigurationSourceRemoteConfig];
  184. // Set fakes to the configurations
  185. FPRFakeRemoteConfig *fakeRemoteConfig = [[FPRFakeRemoteConfig alloc] init];
  186. FPRFakeRemoteConfigFlags *fakeConfigFlags =
  187. [[FPRFakeRemoteConfigFlags alloc] initWithRemoteConfig:(FIRRemoteConfig *)fakeRemoteConfig];
  188. fakeConfigFlags.userDefaults = [[NSUserDefaults alloc] init];
  189. fakeConfigurations.remoteConfigFlags = fakeConfigFlags;
  190. self.logger.configurations = fakeConfigurations;
  191. // Condition (1): when FLL transport percentage = 60% (greater than installation seed)
  192. fakeConfigurations.fllTransportPercentageValue = 60.00;
  193. // Log 2 random Perf events
  194. FPRMSGPerfMetric *event1 = [FPRTestUtils createRandomPerfMetric:@"t1"];
  195. event1.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  196. FPRMSGPerfMetric *event2 = [FPRTestUtils createRandomPerfMetric:@"t2"];
  197. event2.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  198. [self.logger logEvent:event1];
  199. [self.logger logEvent:event2];
  200. // Verify: that both events are logged to FLL
  201. dispatch_sync(self.logger.queue, ^{
  202. // Fetch the logged event
  203. NSArray<GDTCOREvent *> *gdtCorFllEventArray = [self.transportFLLFake logEvents];
  204. NSArray<GDTCOREvent *> *gdtCorCCTEventArray = [self.transportCCTFake logEvents];
  205. XCTAssertTrue(gdtCorFllEventArray.count == 2);
  206. XCTAssertTrue(gdtCorCCTEventArray.count == 0);
  207. });
  208. }
  209. /** Validate if the events are not dispatched to FLL if installation ID seed is greater than
  210. * transport percentage. */
  211. - (void)testEventDispatchedNotToFllWithInstallationIdGreaterThanTransportPercentage {
  212. self.logger.isSimulator = NO;
  213. // Initialize the configurations
  214. FPRFakeConfigurations *fakeConfigurations =
  215. [[FPRFakeConfigurations alloc] initWithSources:FPRConfigurationSourceRemoteConfig];
  216. // Set fakes to the configurations
  217. FPRFakeRemoteConfig *fakeRemoteConfig = [[FPRFakeRemoteConfig alloc] init];
  218. FPRFakeRemoteConfigFlags *fakeConfigFlags =
  219. [[FPRFakeRemoteConfigFlags alloc] initWithRemoteConfig:(FIRRemoteConfig *)fakeRemoteConfig];
  220. fakeConfigFlags.userDefaults = [[NSUserDefaults alloc] init];
  221. fakeConfigurations.remoteConfigFlags = fakeConfigFlags;
  222. self.logger.configurations = fakeConfigurations;
  223. // Condition (1): when FLL transport percentage = 50% (less that installation seed)
  224. fakeConfigurations.fllTransportPercentageValue = 50.00;
  225. // Log 2 random Perf events
  226. FPRMSGPerfMetric *event1 = [FPRTestUtils createRandomPerfMetric:@"t1"];
  227. event1.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  228. FPRMSGPerfMetric *event2 = [FPRTestUtils createRandomPerfMetric:@"t2"];
  229. event2.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  230. [self.logger logEvent:event1];
  231. [self.logger logEvent:event2];
  232. // Verify: that both events are logged to Clearcut
  233. dispatch_sync(self.logger.queue, ^{
  234. // Fetch the logged event
  235. NSArray<GDTCOREvent *> *gdtCorFllEventArray = [self.transportFLLFake logEvents];
  236. NSArray<GDTCOREvent *> *gdtCorCCTEventArray = [self.transportCCTFake logEvents];
  237. XCTAssertTrue(gdtCorFllEventArray.count == 0);
  238. XCTAssertTrue(gdtCorCCTEventArray.count == 2);
  239. });
  240. }
  241. /** Validate if the events are dispatched to FLL if installation ID seed equals to transport
  242. * percentage. */
  243. - (void)testEventDispatchedToFllWithInstallationIdSeedEqualsToTransportPercentage {
  244. self.logger.isSimulator = NO;
  245. // Initialize the configurations
  246. FPRFakeConfigurations *fakeConfigurations =
  247. [[FPRFakeConfigurations alloc] initWithSources:FPRConfigurationSourceRemoteConfig];
  248. // Set fakes to the configurations
  249. FPRFakeRemoteConfig *fakeRemoteConfig = [[FPRFakeRemoteConfig alloc] init];
  250. FPRFakeRemoteConfigFlags *fakeConfigFlags =
  251. [[FPRFakeRemoteConfigFlags alloc] initWithRemoteConfig:(FIRRemoteConfig *)fakeRemoteConfig];
  252. fakeConfigFlags.userDefaults = [[NSUserDefaults alloc] init];
  253. fakeConfigurations.remoteConfigFlags = fakeConfigFlags;
  254. self.logger.configurations = fakeConfigurations;
  255. // Condition (1): when FLL transport percentage = 54% (equal to installation seed)
  256. fakeConfigurations.fllTransportPercentageValue = 54.00;
  257. // Log 2 random Perf events
  258. FPRMSGPerfMetric *event1 = [FPRTestUtils createRandomPerfMetric:@"t1"];
  259. event1.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  260. FPRMSGPerfMetric *event2 = [FPRTestUtils createRandomPerfMetric:@"t2"];
  261. event2.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  262. [self.logger logEvent:event1];
  263. [self.logger logEvent:event2];
  264. // Verify: that both events are logged to FLL
  265. dispatch_sync(self.logger.queue, ^{
  266. // Fetch the logged event
  267. NSArray<GDTCOREvent *> *gdtCorFllEventArray = [self.transportFLLFake logEvents];
  268. NSArray<GDTCOREvent *> *gdtCorCCTEventArray = [self.transportCCTFake logEvents];
  269. XCTAssertTrue(gdtCorFllEventArray.count == 2);
  270. XCTAssertTrue(gdtCorCCTEventArray.count == 0);
  271. });
  272. }
  273. /** Validate if the events are dispatched to FLL if installation transport percentage is set to
  274. * maximum. */
  275. - (void)testEventDispatchedToFllWithMaxTransportPercentage {
  276. self.logger.isSimulator = NO;
  277. // Initialize the configurations
  278. FPRFakeConfigurations *fakeConfigurations =
  279. [[FPRFakeConfigurations alloc] initWithSources:FPRConfigurationSourceRemoteConfig];
  280. // Set fakes to the configurations
  281. FPRFakeRemoteConfig *fakeRemoteConfig = [[FPRFakeRemoteConfig alloc] init];
  282. FPRFakeRemoteConfigFlags *fakeConfigFlags =
  283. [[FPRFakeRemoteConfigFlags alloc] initWithRemoteConfig:(FIRRemoteConfig *)fakeRemoteConfig];
  284. fakeConfigFlags.userDefaults = [[NSUserDefaults alloc] init];
  285. fakeConfigurations.remoteConfigFlags = fakeConfigFlags;
  286. self.logger.configurations = fakeConfigurations;
  287. // Condition: when FLL transport percentage = 100% (maximum %age)
  288. fakeConfigurations.fllTransportPercentageValue = 100.00;
  289. // Log 2 random Perf events
  290. FPRMSGPerfMetric *event1 = [FPRTestUtils createRandomPerfMetric:@"t1"];
  291. event1.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  292. FPRMSGPerfMetric *event2 = [FPRTestUtils createRandomPerfMetric:@"t2"];
  293. event2.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  294. [self.logger logEvent:event1];
  295. [self.logger logEvent:event2];
  296. // Verify: that both events are logged to FLL
  297. dispatch_sync(self.logger.queue, ^{
  298. // Fetch the logged event
  299. NSArray<GDTCOREvent *> *gdtCorFllEventArray = [self.transportFLLFake logEvents];
  300. NSArray<GDTCOREvent *> *gdtCorCCTEventArray = [self.transportCCTFake logEvents];
  301. XCTAssertTrue(gdtCorFllEventArray.count == 2);
  302. XCTAssertTrue(gdtCorCCTEventArray.count == 0);
  303. });
  304. }
  305. /** Validate if the events are dispatched to FLL if installation transport percentage is set to
  306. * minimum. */
  307. - (void)testEventDispatchedNotToFllWithMinTransportPercentage {
  308. self.logger.isSimulator = NO;
  309. // Initialize the configurations
  310. FPRFakeConfigurations *fakeConfigurations =
  311. [[FPRFakeConfigurations alloc] initWithSources:FPRConfigurationSourceRemoteConfig];
  312. // Set fakes to the configurations
  313. FPRFakeRemoteConfig *fakeRemoteConfig = [[FPRFakeRemoteConfig alloc] init];
  314. FPRFakeRemoteConfigFlags *fakeConfigFlags =
  315. [[FPRFakeRemoteConfigFlags alloc] initWithRemoteConfig:(FIRRemoteConfig *)fakeRemoteConfig];
  316. fakeConfigFlags.userDefaults = [[NSUserDefaults alloc] init];
  317. fakeConfigurations.remoteConfigFlags = fakeConfigFlags;
  318. self.logger.configurations = fakeConfigurations;
  319. // Condition: when FLL transport percentage = 0% (minimum %age)
  320. fakeConfigurations.fllTransportPercentageValue = 0.00;
  321. // Log 2 random Perf events
  322. FPRMSGPerfMetric *event1 = [FPRTestUtils createRandomPerfMetric:@"t1"];
  323. event1.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  324. FPRMSGPerfMetric *event2 = [FPRTestUtils createRandomPerfMetric:@"t2"];
  325. event2.applicationInfo.appInstanceId = @"abc"; // Installation ID seed of "abc" is 54.0.
  326. [self.logger logEvent:event1];
  327. [self.logger logEvent:event2];
  328. // Verify: that both events are logged to Clearcut
  329. dispatch_sync(self.logger.queue, ^{
  330. // Fetch the logged event
  331. NSArray<GDTCOREvent *> *gdtCorFllEventArray = [self.transportFLLFake logEvents];
  332. NSArray<GDTCOREvent *> *gdtCorCCTEventArray = [self.transportCCTFake logEvents];
  333. XCTAssertTrue(gdtCorFllEventArray.count == 0);
  334. XCTAssertTrue(gdtCorCCTEventArray.count == 2);
  335. });
  336. }
  337. @end