FIRCrashlyticsReportTests.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // Copyright 2019 Google
  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 <Foundation/Foundation.h>
  15. #import <XCTest/XCTest.h>
  16. #import "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
  17. #import "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
  18. #import "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
  19. #import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
  20. #import "Crashlytics/Crashlytics/Private/FIRCrashlyticsReport_Private.h"
  21. #import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h"
  22. @interface FIRCrashlyticsReportTests : XCTestCase
  23. @end
  24. @implementation FIRCrashlyticsReportTests
  25. - (void)setUp {
  26. [super setUp];
  27. FIRCLSContextBaseInit();
  28. // these values must be set for the internals of logging to work
  29. _firclsContext.readonly->logging.userKVStorage.maxCount = 64;
  30. _firclsContext.readonly->logging.userKVStorage.maxIncrementalCount =
  31. FIRCLSUserLoggingMaxKVEntries;
  32. _firclsContext.readonly->logging.internalKVStorage.maxCount = 32;
  33. _firclsContext.readonly->logging.internalKVStorage.maxIncrementalCount = 16;
  34. _firclsContext.readonly->logging.logStorage.maxSize = 64 * 1000;
  35. _firclsContext.readonly->logging.logStorage.maxEntries = 0;
  36. _firclsContext.readonly->logging.logStorage.restrictBySize = true;
  37. _firclsContext.readonly->logging.logStorage.entryCount = NULL;
  38. _firclsContext.readonly->initialized = true;
  39. }
  40. - (void)tearDown {
  41. FIRCLSContextBaseDeinit();
  42. [super tearDown];
  43. }
  44. - (NSString *)resourcePath {
  45. #if SWIFT_PACKAGE
  46. NSBundle *bundle = SWIFTPM_MODULE_BUNDLE;
  47. return [bundle.resourcePath stringByAppendingPathComponent:@"Data"];
  48. #else
  49. NSBundle *bundle = [NSBundle bundleForClass:[self class]];
  50. return bundle.resourcePath;
  51. #endif
  52. }
  53. - (NSString *)pathForResource:(NSString *)name {
  54. return [[self resourcePath] stringByAppendingPathComponent:name];
  55. }
  56. - (FIRCLSInternalReport *)createTempCopyOfInternalReportWithName:(NSString *)name {
  57. NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:name];
  58. // make sure to remove anything that was there previously
  59. [[NSFileManager defaultManager] removeItemAtPath:tempPath error:nil];
  60. NSString *resourcePath = [self pathForResource:name];
  61. [[NSFileManager defaultManager] copyItemAtPath:resourcePath toPath:tempPath error:nil];
  62. return [[FIRCLSInternalReport alloc] initWithPath:tempPath];
  63. }
  64. - (FIRCrashlyticsReport *)createTempCopyOfReportWithName:(NSString *)name {
  65. FIRCLSInternalReport *internalReport = [self createTempCopyOfInternalReportWithName:name];
  66. return [[FIRCrashlyticsReport alloc] initWithInternalReport:internalReport];
  67. }
  68. #pragma mark - Public Getter Methods
  69. - (void)testPropertiesFromMetadatFile {
  70. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"metadata_only_report"];
  71. XCTAssertEqualObjects(@"772929a7f21f4ad293bb644668f257cd", report.reportID);
  72. XCTAssertEqualObjects([NSDate dateWithTimeIntervalSince1970:1423944888], report.dateCreated);
  73. }
  74. #pragma mark - Public Setter Methods
  75. - (void)testSetUserID {
  76. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"metadata_only_report"];
  77. [report setUserID:@"12345-6"];
  78. NSArray *entries = FIRCLSFileReadSections(
  79. [[report.internalReport pathForContentFile:FIRCLSReportInternalIncrementalKVFile]
  80. fileSystemRepresentation],
  81. false, nil);
  82. XCTAssertEqual([entries count], 1, @"");
  83. XCTAssertEqualObjects(entries[0][@"kv"][@"key"],
  84. FIRCLSFileHexEncodeString([FIRCLSUserIdentifierKey UTF8String]), @"");
  85. XCTAssertEqualObjects(entries[0][@"kv"][@"value"], FIRCLSFileHexEncodeString("12345-6"), @"");
  86. }
  87. - (void)testClearUserID {
  88. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"metadata_only_report"];
  89. // Add a user ID
  90. [report setUserID:@"12345-6"];
  91. NSArray *entries = FIRCLSFileReadSections(
  92. [[report.internalReport pathForContentFile:FIRCLSReportInternalIncrementalKVFile]
  93. fileSystemRepresentation],
  94. false, nil);
  95. XCTAssertEqual([entries count], 1, @"");
  96. // Now remove it
  97. [report setUserID:nil];
  98. entries = FIRCLSFileReadSections(
  99. [[report.internalReport pathForContentFile:FIRCLSReportInternalCompactedKVFile]
  100. fileSystemRepresentation],
  101. false, nil);
  102. XCTAssertEqual([entries count], 0, @"");
  103. }
  104. - (void)testCustomKeysNoExisting {
  105. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"metadata_only_report"];
  106. [report setCustomValue:@"hello" forKey:@"mykey"];
  107. [report setCustomValue:@"goodbye" forKey:@"anotherkey"];
  108. [report setCustomKeysAndValues:@{
  109. @"is_test" : @(YES),
  110. @"test_number" : @(10),
  111. }];
  112. NSArray *entries = FIRCLSFileReadSections(
  113. [[report.internalReport pathForContentFile:FIRCLSReportUserIncrementalKVFile]
  114. fileSystemRepresentation],
  115. false, nil);
  116. XCTAssertEqual([entries count], 4, @"");
  117. XCTAssertEqualObjects(entries[0][@"kv"][@"key"], FIRCLSFileHexEncodeString("mykey"), @"");
  118. XCTAssertEqualObjects(entries[0][@"kv"][@"value"], FIRCLSFileHexEncodeString("hello"), @"");
  119. XCTAssertEqualObjects(entries[1][@"kv"][@"key"], FIRCLSFileHexEncodeString("anotherkey"), @"");
  120. XCTAssertEqualObjects(entries[1][@"kv"][@"value"], FIRCLSFileHexEncodeString("goodbye"), @"");
  121. XCTAssertEqualObjects(entries[2][@"kv"][@"key"], FIRCLSFileHexEncodeString("is_test"), @"");
  122. XCTAssertEqualObjects(entries[2][@"kv"][@"value"], FIRCLSFileHexEncodeString("1"), @"");
  123. XCTAssertEqualObjects(entries[3][@"kv"][@"key"], FIRCLSFileHexEncodeString("test_number"), @"");
  124. XCTAssertEqualObjects(entries[3][@"kv"][@"value"], FIRCLSFileHexEncodeString("10"), @"");
  125. }
  126. - (void)testCustomKeysWithExisting {
  127. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"ios_all_files_crash"];
  128. [report setCustomValue:@"hello" forKey:@"mykey"];
  129. [report setCustomValue:@"goodbye" forKey:@"anotherkey"];
  130. [report setCustomKeysAndValues:@{
  131. @"is_test" : @(YES),
  132. @"test_number" : @(10),
  133. }];
  134. NSArray *entries = FIRCLSFileReadSections(
  135. [[report.internalReport pathForContentFile:FIRCLSReportUserIncrementalKVFile]
  136. fileSystemRepresentation],
  137. false, nil);
  138. XCTAssertEqual([entries count], 5, @"");
  139. XCTAssertEqualObjects(entries[1][@"kv"][@"key"], FIRCLSFileHexEncodeString("mykey"), @"");
  140. XCTAssertEqualObjects(entries[1][@"kv"][@"value"], FIRCLSFileHexEncodeString("hello"), @"");
  141. XCTAssertEqualObjects(entries[2][@"kv"][@"key"], FIRCLSFileHexEncodeString("anotherkey"), @"");
  142. XCTAssertEqualObjects(entries[2][@"kv"][@"value"], FIRCLSFileHexEncodeString("goodbye"), @"");
  143. XCTAssertEqualObjects(entries[3][@"kv"][@"key"], FIRCLSFileHexEncodeString("is_test"), @"");
  144. XCTAssertEqualObjects(entries[3][@"kv"][@"value"], FIRCLSFileHexEncodeString("1"), @"");
  145. XCTAssertEqualObjects(entries[4][@"kv"][@"key"], FIRCLSFileHexEncodeString("test_number"), @"");
  146. XCTAssertEqualObjects(entries[4][@"kv"][@"value"], FIRCLSFileHexEncodeString("10"), @"");
  147. }
  148. - (void)testClearCustomKeys {
  149. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"metadata_only_report"];
  150. // Add keys
  151. [report setCustomValue:@"hello" forKey:@"mykey"];
  152. [report setCustomValue:@"goodbye" forKey:@"anotherkey"];
  153. [report setCustomKeysAndValues:@{
  154. @"is_test" : @(YES),
  155. @"test_number" : @(10),
  156. }];
  157. NSArray *entries = FIRCLSFileReadSections(
  158. [[report.internalReport pathForContentFile:FIRCLSReportUserIncrementalKVFile]
  159. fileSystemRepresentation],
  160. false, nil);
  161. XCTAssertEqual([entries count], 4, @"");
  162. // Now remove them
  163. [report setCustomValue:nil forKey:@"mykey"];
  164. [report setCustomValue:nil forKey:@"anotherkey"];
  165. entries = FIRCLSFileReadSections(
  166. [[report.internalReport pathForContentFile:FIRCLSReportUserIncrementalKVFile]
  167. fileSystemRepresentation],
  168. false, nil);
  169. [report setCustomKeysAndValues:@{
  170. @"is_test" : [NSNull null],
  171. @"test_number" : [NSNull null],
  172. }];
  173. entries = FIRCLSFileReadSections(
  174. [[report.internalReport pathForContentFile:FIRCLSReportInternalCompactedKVFile]
  175. fileSystemRepresentation],
  176. false, nil);
  177. XCTAssertEqual([entries count], 0, @"");
  178. }
  179. - (void)testCustomKeysLimits {
  180. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"ios_all_files_crash"];
  181. // Write a bunch of keys and values
  182. for (int i = 0; i < 120; i++) {
  183. NSString *key = [NSString stringWithFormat:@"key_%i", i];
  184. [report setCustomValue:@"hello" forKey:key];
  185. }
  186. NSArray *entriesI = FIRCLSFileReadSections(
  187. [[report.internalReport pathForContentFile:FIRCLSReportUserIncrementalKVFile]
  188. fileSystemRepresentation],
  189. false, nil);
  190. NSArray *entriesC = FIRCLSFileReadSections(
  191. [[report.internalReport pathForContentFile:FIRCLSReportUserCompactedKVFile]
  192. fileSystemRepresentation],
  193. false, nil);
  194. // One of these should be the max (64), and one should be the number of written keys modulo 64
  195. // (eg. 56 == (120 mod 64))
  196. XCTAssertEqual(entriesI.count, 56, @"");
  197. XCTAssertEqual(entriesC.count, 64, @"");
  198. }
  199. - (void)testLogsNoExisting {
  200. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"metadata_only_report"];
  201. [report log:@"Normal log without formatting"];
  202. [report logWithFormat:@"%@, %@", @"First", @"Second"];
  203. NSArray *entries = FIRCLSFileReadSections(
  204. [[report.internalReport pathForContentFile:FIRCLSReportLogAFile] fileSystemRepresentation],
  205. false, nil);
  206. XCTAssertEqual([entries count], 2, @"");
  207. XCTAssertEqualObjects(entries[0][@"log"][@"msg"],
  208. FIRCLSFileHexEncodeString("Normal log without formatting"), @"");
  209. XCTAssertEqualObjects(entries[1][@"log"][@"msg"], FIRCLSFileHexEncodeString("First, Second"),
  210. @"");
  211. }
  212. - (void)testLogsWithExisting {
  213. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"ios_all_files_crash"];
  214. [report log:@"Normal log without formatting"];
  215. [report logWithFormat:@"%@, %@", @"First", @"Second"];
  216. NSArray *entries = FIRCLSFileReadSections(
  217. [[report.internalReport pathForContentFile:FIRCLSReportLogAFile] fileSystemRepresentation],
  218. false, nil);
  219. XCTAssertEqual([entries count], 8, @"");
  220. XCTAssertEqualObjects(entries[6][@"log"][@"msg"],
  221. FIRCLSFileHexEncodeString("Normal log without formatting"), @"");
  222. XCTAssertEqualObjects(entries[7][@"log"][@"msg"], FIRCLSFileHexEncodeString("First, Second"),
  223. @"");
  224. }
  225. - (void)testLogLimits {
  226. FIRCrashlyticsReport *report = [self createTempCopyOfReportWithName:@"metadata_only_report"];
  227. for (int i = 0; i < 2000; i++) {
  228. [report log:@"0123456789"];
  229. }
  230. unsigned long long sizeA = [[[NSFileManager defaultManager]
  231. attributesOfItemAtPath:[report.internalReport pathForContentFile:FIRCLSReportLogAFile]
  232. error:nil] fileSize];
  233. unsigned long long sizeB = [[[NSFileManager defaultManager]
  234. attributesOfItemAtPath:[report.internalReport pathForContentFile:FIRCLSReportLogBFile]
  235. error:nil] fileSize];
  236. NSArray *entriesA = FIRCLSFileReadSections(
  237. [[report.internalReport pathForContentFile:FIRCLSReportLogAFile] fileSystemRepresentation],
  238. false, nil);
  239. NSArray *entriesB = FIRCLSFileReadSections(
  240. [[report.internalReport pathForContentFile:FIRCLSReportLogBFile] fileSystemRepresentation],
  241. false, nil);
  242. // If these numbers have changed, the goal is to validate that the size of log_a and log_b are
  243. // under the limit, logStorage.maxSize (64 * 1000). These numbers don't need to be exact so if
  244. // they fluctuate then we might just need to accept a range in these tests.
  245. XCTAssertEqual(entriesB.count + entriesA.count, 2000, @"");
  246. XCTAssertEqual(sizeA, 64 * 1000 + 20, @"");
  247. XCTAssertEqual(sizeB, 55980, @"");
  248. }
  249. @end