FIRCLSReportAdapterTests.m 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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 <Foundation/Foundation.h>
  15. #import <XCTest/XCTest.h>
  16. #import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.h"
  17. #import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.h"
  18. #import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.h"
  19. #import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h"
  20. #import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter_Private.h"
  21. #import "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
  22. #import "Crashlytics/UnitTests/Mocks/FIRMockInstallations.h"
  23. #import <GoogleDataTransport/GoogleDataTransport.h>
  24. @interface FIRCLSReportAdapterTests : XCTestCase
  25. @property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
  26. @end
  27. @implementation FIRCLSReportAdapterTests
  28. - (void)setUp {
  29. FIRMockInstallations *iid = [[FIRMockInstallations alloc] initWithFID:@"test_token"];
  30. self.installIDModel = [[FIRCLSInstallIdentifierModel alloc] initWithInstallations:iid];
  31. }
  32. /// Attempt sending a proto report to the reporting endpoint
  33. - (void)testSendProtoReport {
  34. NSString *minCrash =
  35. [[FIRCLSReportAdapterTests resourcePath] stringByAppendingPathComponent:@"bare_min_crash"];
  36. FIRCLSReportAdapter *adapter =
  37. [[FIRCLSReportAdapter alloc] initWithPath:minCrash
  38. googleAppId:@"1:17586535263:ios:83778f4dc7e8a26ef794ea"
  39. installIDModel:self.installIDModel];
  40. GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"1206"
  41. transformers:nil
  42. target:kGDTCORTargetCSH];
  43. GDTCOREvent *event = [transport eventForTransport];
  44. event.dataObject = adapter;
  45. event.qosTier = GDTCOREventQoSFast; // Bypass batching and have the event get sent out ASAP
  46. [transport sendDataEvent:event];
  47. }
  48. /// This test is useful for testing the binary output of the proto message
  49. - (void)testProtoOutput {
  50. NSString *minCrash =
  51. [[FIRCLSReportAdapterTests resourcePath] stringByAppendingPathComponent:@"bare_min_crash"];
  52. FIRCLSReportAdapter *adapter =
  53. [[FIRCLSReportAdapter alloc] initWithPath:minCrash
  54. googleAppId:@"1:17586535263:ios:83778f4dc7e8a26ef794ea"
  55. installIDModel:self.installIDModel];
  56. NSData *data = adapter.transportBytes;
  57. NSError *error = nil;
  58. NSString *outputPath =
  59. [[FIRCLSReportAdapterTests resourcePath] stringByAppendingPathComponent:@"output.proto"];
  60. [data writeToFile:outputPath options:NSDataWritingAtomic error:&error];
  61. NSLog(@"Output path: %@", outputPath);
  62. if (error) {
  63. NSLog(@"Write returned error: %@", [error localizedDescription]);
  64. }
  65. // Put a breakpoint here to copy the file from the output path.
  66. }
  67. /// It is important that a crash does not occur when reading persisted crash files
  68. /// Verify various invalid input cases.
  69. - (void)testInvalidRecordCases {
  70. id adapter __unused = [[FIRCLSReportAdapter alloc] initWithPath:@"nonExistentPath"
  71. googleAppId:@"appID"
  72. installIDModel:self.installIDModel];
  73. id application __unused = [[FIRCLSRecordApplication alloc] initWithDict:nil];
  74. id host __unused = [[FIRCLSRecordHost alloc] initWithDict:nil];
  75. id identity __unused = [[FIRCLSRecordIdentity alloc] initWithDict:nil];
  76. NSDictionary *emptyDict = [[NSDictionary alloc] init];
  77. id application2 __unused = [[FIRCLSRecordApplication alloc] initWithDict:emptyDict];
  78. id host2 __unused = [[FIRCLSRecordHost alloc] initWithDict:emptyDict];
  79. id identity2 __unused = [[FIRCLSRecordIdentity alloc] initWithDict:emptyDict];
  80. }
  81. - (void)testCorruptMetadataCLSRecordFile {
  82. id adapter __unused = [self adapterForCorruptMetadata];
  83. }
  84. - (void)testRecordMetadataFile {
  85. FIRCLSReportAdapter *adapter = [self adapterForValidMetadata];
  86. // Verify identity
  87. XCTAssertTrue([adapter.identity.build_version isEqualToString:@"4.0.0-beta.1"]);
  88. // Verify host
  89. XCTAssertTrue([adapter.host.platform isEqualToString:@"ios"]);
  90. // Verify application
  91. XCTAssertTrue([adapter.application.build_version isEqualToString:@"1"]);
  92. XCTAssertTrue([adapter.application.display_version isEqualToString:@"1.0"]);
  93. }
  94. - (void)testReportProto {
  95. FIRCLSReportAdapter *adapter = [self adapterForAllCrashes];
  96. google_crashlytics_Report report = [adapter protoReport];
  97. XCTAssertTrue([self isPBData:report.sdk_version equalToString:adapter.identity.build_version]);
  98. XCTAssertTrue([self isPBData:report.gmp_app_id equalToString:@"appID"]);
  99. XCTAssertEqual(report.platform, google_crashlytics_Platforms_IOS);
  100. XCTAssertTrue([self isPBData:report.installation_uuid
  101. equalToString:self.installIDModel.installID]);
  102. XCTAssertTrue([self isPBData:report.display_version
  103. equalToString:adapter.application.display_version]);
  104. // Files payload
  105. XCTAssertEqual(report.apple_payload.files_count, 11);
  106. NSArray<NSString *> *clsRecords = adapter.clsRecordFilePaths;
  107. for (NSUInteger i = 0; i < clsRecords.count; i++) {
  108. XCTAssertTrue([self isPBData:report.apple_payload.files[i].filename
  109. equalToString:clsRecords[i].lastPathComponent]);
  110. NSData *data = [NSData dataWithContentsOfFile:clsRecords[i] options:0 error:nil];
  111. XCTAssertTrue([self isPBData:report.apple_payload.files[i].contents equalToData:data]);
  112. }
  113. }
  114. // Helper functions
  115. #pragma mark - Helper Functions
  116. - (FIRCLSReportAdapter *)adapterForAllCrashes {
  117. return [[FIRCLSReportAdapter alloc]
  118. initWithPath:[[FIRCLSReportAdapterTests resourcePath]
  119. stringByAppendingPathComponent:@"ios_all_files_crash"]
  120. googleAppId:@"appID"
  121. installIDModel:self.installIDModel];
  122. }
  123. - (FIRCLSReportAdapter *)adapterForCorruptMetadata {
  124. return [[FIRCLSReportAdapter alloc]
  125. initWithPath:[[FIRCLSReportAdapterTests resourcePath]
  126. stringByAppendingPathComponent:@"corrupt_metadata"]
  127. googleAppId:@"appID"
  128. installIDModel:self.installIDModel];
  129. }
  130. - (FIRCLSReportAdapter *)adapterForValidMetadata {
  131. return [[FIRCLSReportAdapter alloc]
  132. initWithPath:[[FIRCLSReportAdapterTests resourcePath]
  133. stringByAppendingPathComponent:@"valid_metadata"]
  134. googleAppId:@"appID"
  135. installIDModel:self.installIDModel];
  136. }
  137. + (NSString *)resourcePath {
  138. return [[NSBundle bundleForClass:[self class]] resourcePath];
  139. }
  140. #pragma mark - Assertion Helpers for NanoPB Types
  141. - (BOOL)isPBData:(pb_bytes_array_t *)pbString equalToString:(NSString *)str {
  142. pb_bytes_array_t *expected = FIRCLSEncodeString(str);
  143. return [self isPBArray:pbString equalToArray:expected];
  144. }
  145. - (BOOL)isPBData:(pb_bytes_array_t *)pbString equalToData:(NSData *)data {
  146. pb_bytes_array_t *expected = FIRCLSEncodeData(data);
  147. return [self isPBArray:pbString equalToArray:expected];
  148. }
  149. - (BOOL)isPBArray:(pb_bytes_array_t *)array equalToArray:(pb_bytes_array_t *)expected {
  150. // Treat the empty string as the same as a missing field
  151. if ((!array) && expected->size == 0) {
  152. return true;
  153. }
  154. if (array->size != expected->size) {
  155. return false;
  156. }
  157. for (int i = 0; i < array->size; i++) {
  158. if (expected->bytes[i] != array->bytes[i]) {
  159. return false;
  160. }
  161. }
  162. return true;
  163. }
  164. @end