FPRClientTest.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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 "FirebaseCore/Extension/FirebaseCoreInternal.h"
  16. #import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h"
  17. #import "FirebasePerformance/Sources/FPRClient+Private.h"
  18. #import "FirebasePerformance/Sources/FPRClient.h"
  19. #import "FirebasePerformance/Sources/FPRNanoPbUtils.h"
  20. #import "FirebasePerformance/Sources/Loggers/FPRGDTLogger.h"
  21. #import "FirebasePerformance/Sources/Loggers/FPRGDTLogger_Private.h"
  22. #import "FirebasePerformance/Tests/Unit/Configurations/FPRFakeRemoteConfig.h"
  23. #import "FirebasePerformance/Tests/Unit/FPRTestCase.h"
  24. #import "FirebasePerformance/Tests/Unit/FPRTestUtils.h"
  25. #import "FirebasePerformance/Tests/Unit/Fakes/FPRFakeConfigurations.h"
  26. #import "FirebasePerformance/Tests/Unit/Fakes/FPRFakeInstallations.h"
  27. #import <OCMock/OCMock.h>
  28. #import "SharedTestUtilities/GDTCORTransportFake.h"
  29. NSString *const kFPRMockInstallationId = @"mockId";
  30. @interface FPRClientTest : FPRTestCase
  31. /** Configuration which can be assigned as a fake object for event dispatch control. */
  32. @property(nonatomic) FPRConfigurations *configurations;
  33. /** Fireperf client object which can be used for fake object injection and assertion . */
  34. @property(nonatomic) FPRClient *client;
  35. @end
  36. @implementation FPRClientTest
  37. - (void)setUp {
  38. [super setUp];
  39. // Arrange installations object.
  40. FPRFakeInstallations *installations = [FPRFakeInstallations installations];
  41. self.client = [[FPRClient alloc] init];
  42. installations.identifier = kFPRMockInstallationId;
  43. self.client.installations = (FIRInstallations *)installations;
  44. // Arrange remote config object.
  45. FPRFakeConfigurations *fakeConfigs =
  46. [[FPRFakeConfigurations alloc] initWithSources:FPRConfigurationSourceRemoteConfig];
  47. self.configurations = fakeConfigs;
  48. fakeConfigs.dataCollectionEnabled = YES;
  49. fakeConfigs.sdkEnabled = YES;
  50. self.client.configuration = self.configurations;
  51. // Arrange gdtLogger object for event dispatch.
  52. self.client.gdtLogger = [[FPRGDTLogger alloc] initWithLogSource:1];
  53. GDTCORTransportFake *fakeGdtTransport =
  54. [[GDTCORTransportFake alloc] initWithMappingID:@"1" transformers:nil target:kGDTCORTargetFLL];
  55. self.client.gdtLogger.gdtfllTransport = fakeGdtTransport;
  56. }
  57. /** Validates if the gdtTransport logger has received trace perfMetric. */
  58. - (void)testLogAndProcessEventsForTrace {
  59. // Trace type PerfMetric for event dispatch.
  60. firebase_perf_v1_PerfMetric perfMetric = [FPRTestUtils createRandomPerfMetric:@"RandomTrace"];
  61. // Act on event logging call.
  62. [self.client processAndLogEvent:perfMetric];
  63. firebase_perf_v1_PerfMetric expectedMetric = perfMetric;
  64. expectedMetric.application_info.app_instance_id = FPREncodeString(kFPRMockInstallationId);
  65. // Wait for async job to execute event logging.
  66. dispatch_group_wait(self.client.eventsQueueGroup, DISPATCH_TIME_FOREVER);
  67. // Validate the event is received by gdtTransport logger.
  68. dispatch_sync(self.client.gdtLogger.queue, ^{
  69. GDTCORTransportFake *fakeGdtTransport =
  70. (GDTCORTransportFake *)self.client.gdtLogger.gdtfllTransport;
  71. XCTAssertEqual(fakeGdtTransport.logEvents.count, 1);
  72. GDTCOREvent *event = fakeGdtTransport.logEvents.firstObject;
  73. XCTAssertNotNil(
  74. FPRDecodeString([(FPRGDTEvent *)event.dataObject metric].application_info.app_instance_id));
  75. XCTAssertEqualObjects([event.dataObject transportBytes],
  76. [[FPRGDTEvent gdtEventForPerfMetric:expectedMetric] transportBytes]);
  77. });
  78. }
  79. /** Validates if the gdtTransport logger has received network trace perfMetric. */
  80. - (void)testLogAndProcessEventsForNetworkTrace {
  81. // Network type PerfMetric for event dispatch.
  82. firebase_perf_v1_PerfMetric perfMetric =
  83. [FPRTestUtils createRandomNetworkPerfMetric:@"https://abc.xyz"];
  84. // Act on event logging call.
  85. [self.client processAndLogEvent:perfMetric];
  86. firebase_perf_v1_PerfMetric expectedMetric = perfMetric;
  87. expectedMetric.application_info.app_instance_id = FPREncodeString(kFPRMockInstallationId);
  88. // Wait for async job to execute event logging.
  89. dispatch_group_wait(self.client.eventsQueueGroup, DISPATCH_TIME_FOREVER);
  90. // Validate the event is received by gdtTransport logger.
  91. dispatch_sync(self.client.gdtLogger.queue, ^{
  92. GDTCORTransportFake *fakeGdtTransport =
  93. (GDTCORTransportFake *)self.client.gdtLogger.gdtfllTransport;
  94. XCTAssertEqual(fakeGdtTransport.logEvents.count, 1);
  95. GDTCOREvent *event = fakeGdtTransport.logEvents.firstObject;
  96. XCTAssertNotNil(
  97. FPRDecodeString([(FPRGDTEvent *)event.dataObject metric].application_info.app_instance_id));
  98. XCTAssertEqualObjects([event.dataObject transportBytes],
  99. [[FPRGDTEvent gdtEventForPerfMetric:expectedMetric] transportBytes]);
  100. });
  101. }
  102. /** Validates if the gdtTransport logger has received session gauge perfMetric. */
  103. - (void)testLogAndProcessEventsForGauge {
  104. // Gauge type PerfMetric for event dispatch.
  105. firebase_perf_v1_PerfMetric perfMetric = [FPRTestUtils createRandomGaugePerfMetric];
  106. // Act on event logging call.
  107. [self.client processAndLogEvent:perfMetric];
  108. firebase_perf_v1_PerfMetric expectedMetric = perfMetric;
  109. expectedMetric.application_info.app_instance_id = FPREncodeString(kFPRMockInstallationId);
  110. // Wait for async job to execute event logging.
  111. dispatch_group_wait(self.client.eventsQueueGroup, DISPATCH_TIME_FOREVER);
  112. // Validate the event is received by gdtTransport logger.
  113. dispatch_sync(self.client.gdtLogger.queue, ^{
  114. GDTCORTransportFake *fakeGdtTransport =
  115. (GDTCORTransportFake *)self.client.gdtLogger.gdtfllTransport;
  116. XCTAssertEqual(fakeGdtTransport.logEvents.count, 1);
  117. GDTCOREvent *event = fakeGdtTransport.logEvents.firstObject;
  118. XCTAssertNotNil(
  119. FPRDecodeString([(FPRGDTEvent *)event.dataObject metric].application_info.app_instance_id));
  120. XCTAssertEqualObjects([event.dataObject transportBytes],
  121. [[FPRGDTEvent gdtEventForPerfMetric:expectedMetric] transportBytes]);
  122. });
  123. }
  124. /** Validates if the gdtTransport logger will not receive event when data collection is disabled. */
  125. - (void)testLogAndProcessEventsNotDispatchWhenDisabled {
  126. // Trace type PerfMetric for event dispatch.
  127. firebase_perf_v1_PerfMetric perfMetric = [FPRTestUtils createRandomPerfMetric:@"RandomTrace"];
  128. // Act on event logging call when data collection is disabled.
  129. self.configurations.dataCollectionEnabled = NO;
  130. [self.client processAndLogEvent:perfMetric];
  131. // Wait for async job to execute event logging.
  132. dispatch_group_wait(self.client.eventsQueueGroup, DISPATCH_TIME_FOREVER);
  133. // Validate the event is not received by gdtTransport logger.
  134. dispatch_sync(self.client.gdtLogger.queue, ^{
  135. GDTCORTransportFake *fakeGdtTransport =
  136. (GDTCORTransportFake *)self.client.gdtLogger.gdtfllTransport;
  137. XCTAssertEqual(fakeGdtTransport.logEvents.count, 0);
  138. });
  139. }
  140. /** Validates if the gdtTransport logger will resume receiving event when data collection is
  141. * re-enabled. */
  142. - (void)testLogAndProcessEventsAfterReenabled {
  143. // Trace type PerfMetric for event dispatch.
  144. firebase_perf_v1_PerfMetric perfMetric = [FPRTestUtils createRandomPerfMetric:@"RandomTrace"];
  145. // Act on event logging call when data collection is disabled.
  146. self.configurations.dataCollectionEnabled = NO;
  147. [self.client processAndLogEvent:perfMetric];
  148. // Wait for async job to execute event logging.
  149. dispatch_group_wait(self.client.eventsQueueGroup, DISPATCH_TIME_FOREVER);
  150. // Validate the event is not received by gdtTransport logger.
  151. dispatch_sync(self.client.gdtLogger.queue, ^{
  152. GDTCORTransportFake *fakeGdtTransport =
  153. (GDTCORTransportFake *)self.client.gdtLogger.gdtfllTransport;
  154. XCTAssertEqual(fakeGdtTransport.logEvents.count, 0);
  155. });
  156. // Act on event logging call after re-enable data collection.
  157. self.configurations.dataCollectionEnabled = YES;
  158. [self.client processAndLogEvent:perfMetric];
  159. // Wait for async job to execute event logging.
  160. dispatch_group_wait(self.client.eventsQueueGroup, DISPATCH_TIME_FOREVER);
  161. // Validate the event is received by gdtTransport logger.
  162. dispatch_sync(self.client.gdtLogger.queue, ^{
  163. GDTCORTransportFake *fakeGdtTransport =
  164. (GDTCORTransportFake *)self.client.gdtLogger.gdtfllTransport;
  165. XCTAssertEqual(fakeGdtTransport.logEvents.count, 1);
  166. });
  167. }
  168. /** Validates that the Clearcut log directory removal method is called. */
  169. - (void)testClearcutLogDirectoryCleanupInitiates {
  170. id clientMock = OCMClassMock(self.client.class);
  171. [self.client startWithConfiguration:[[FPRConfiguration alloc] initWithAppID:@"RandomAppId"
  172. APIKey:nil
  173. autoPush:YES]
  174. error:nil];
  175. // Wait for async job to initiate cleanup logic.
  176. dispatch_group_wait(self.client.eventsQueueGroup, DISPATCH_TIME_FOREVER);
  177. OCMVerify([clientMock cleanupClearcutCacheDirectory]);
  178. }
  179. /**
  180. * Validates that the log directory path in the cache directory created for Clearcut logs storage
  181. * gets removed (if exist).
  182. */
  183. - (void)testValidateClearcutLogDirectoryCleanupIfExists {
  184. // Create the log directory and make sure it exists.
  185. NSString *logDirectoryPath = [FPRClient logDirectoryPath];
  186. [[NSFileManager defaultManager] createDirectoryAtPath:logDirectoryPath
  187. withIntermediateDirectories:YES
  188. attributes:nil
  189. error:nil];
  190. BOOL logDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:logDirectoryPath];
  191. XCTAssertTrue(logDirectoryExists);
  192. [FPRClient cleanupClearcutCacheDirectory];
  193. logDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:logDirectoryPath];
  194. XCTAssertFalse(logDirectoryExists);
  195. }
  196. /**
  197. * Validates that the Clearcut log directory path removal logic doesn't explode if directory doesn't
  198. * exist.
  199. */
  200. - (void)testValidateClearcutLogDirectoryCleanupIfNotExists {
  201. NSString *logDirectoryPath = [FPRClient logDirectoryPath];
  202. BOOL logDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:logDirectoryPath];
  203. XCTAssertFalse(logDirectoryExists);
  204. XCTAssertNoThrow([FPRClient cleanupClearcutCacheDirectory]);
  205. }
  206. #pragma mark - Component Registration Tests
  207. - (void)testRegistersAsLibrary {
  208. // Configure a test FIRApp.
  209. NSString *appName = @"__FIRAPP_DEFAULT";
  210. [FIRApp configureWithName:appName options:[self fakeOptions]];
  211. FIRApp *app = [FIRApp appNamed:appName];
  212. // Attempt to fetch the component and verify it's a valid instance.
  213. id<FIRPerformanceProvider> provider = FIR_COMPONENT(FIRPerformanceProvider, app.container);
  214. XCTAssertNotNil(provider);
  215. // Ensure that the instance that comes from the container is cached.
  216. id<FIRPerformanceProvider> sameProvider = FIR_COMPONENT(FIRPerformanceProvider, app.container);
  217. XCTAssertNotNil(sameProvider);
  218. XCTAssertEqual(provider, sameProvider);
  219. }
  220. - (void)testFailsRegistrationForNonDefaultApp {
  221. // Configure a test FIRApp.
  222. NSString *appName = @"some_random_app";
  223. [FIRApp configureWithName:appName options:[self fakeOptions]];
  224. FIRApp *app = [FIRApp appNamed:appName];
  225. // Attempt to fetch the component and verify it's a valid instance.
  226. id<FIRPerformanceProvider> provider = FIR_COMPONENT(FIRPerformanceProvider, app.container);
  227. XCTAssertNil(provider);
  228. }
  229. #pragma mark - Helpers
  230. - (FIROptions *)fakeOptions {
  231. FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:@"1:123:ios:123abc"
  232. GCMSenderID:@"correct_gcm_sender_id"];
  233. options.APIKey = @"AIzaSy-ApiKeyWithValidFormat_0123456789";
  234. options.projectID = @"project-id";
  235. return options;
  236. }
  237. @end