Skip to content

Commit 10a7766

Browse files
authored
Add FIRCLSReportUploader unit tests for supporting multiple endpoints (#4978)
1 parent 2855cf1 commit 10a7766

File tree

10 files changed

+243
-44
lines changed

10 files changed

+243
-44
lines changed

Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.m

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,10 @@ - (BOOL)prepareAndSubmitReport:(FIRCLSInternalReport *)report
114114

115115
if (self.dataSource.settings.shouldUseNewReportEndpoint) {
116116
// For the new endpoint, just move the .clsrecords from "processing" -> "prepared"
117-
packagedPath =
118-
[self.fileManager.preparedPath stringByAppendingPathComponent:report.directoryName];
119-
NSError *moveError = nil;
120-
[self.fileManager moveItemAtPath:report.path toPath:packagedPath error:&moveError];
121-
if (moveError) {
117+
if (![self.fileManager moveItemAtPath:report.path
118+
toDirectory:self.fileManager.preparedPath]) {
122119
FIRCLSErrorLog(@"Unable to move report to prepared");
120+
return;
123121
}
124122
} else {
125123
// For the legacy endpoint, continue generate the multipartmime file in "prepared-legacy"
@@ -203,6 +201,11 @@ - (BOOL)uploadPackagedReportAtPath:(NSString *)path
203201
BOOL isNewPreparedPath = ![path containsString:self.fileManager.legacyPreparedPath];
204202

205203
if (isNewPreparedPath && self.dataSource.settings.shouldUseNewReportEndpoint) {
204+
if (![dataCollectionToken isValid]) {
205+
FIRCLSErrorLog(@"A report upload was requested with an invalid data collection token.");
206+
return NO;
207+
}
208+
206209
FIRCLSReportAdapter *adapter =
207210
[[FIRCLSReportAdapter alloc] initWithPath:path
208211
googleAppId:self.dataSource.googleAppID

Crashlytics/UnitTests/FIRCLSReportUploaderTests.m

Lines changed: 175 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@
1919
#import "FABMockApplicationIdentifierModel.h"
2020
#import "FIRCLSApplication.h"
2121
#include "FIRCLSConstants.h"
22+
#include "FIRCLSDataCollectionToken.h"
2223
#include "FIRCLSDefines.h"
2324
#include "FIRCLSFileManager.h"
25+
#include "FIRCLSInternalReport.h"
26+
#include "FIRCLSMockFileManager.h"
27+
#include "FIRCLSMockNetworkClient.h"
2428
#include "FIRCLSMockSettings.h"
2529
#include "FIRCLSSettings.h"
2630
#include "FIRMockGDTCoreTransport.h"
@@ -31,9 +35,13 @@ @interface FIRCLSReportUploaderTests
3135
: XCTestCase <FIRCLSReportUploaderDelegate, FIRCLSReportUploaderDataSource>
3236

3337
@property(nonatomic, strong) FIRCLSReportUploader *uploader;
34-
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
38+
@property(nonatomic, strong) FIRCLSMockFileManager *fileManager;
3539
@property(nonatomic, strong) NSOperationQueue *queue;
36-
@property(nonatomic, strong) NSURL *url;
40+
@property(nonatomic, strong) FIRCLSMockNetworkClient *networkClient;
41+
42+
// Add mock prefix to names as there are naming conflicts with FIRCLSReportUploaderDelegate
43+
@property(nonatomic, strong) FIRMockGDTCORTransport *mockDataTransport;
44+
@property(nonatomic, strong) FIRCLSMockSettings *mockSettings;
3745

3846
@end
3947

@@ -42,21 +50,24 @@ @implementation FIRCLSReportUploaderTests
4250
- (void)setUp {
4351
[super setUp];
4452

53+
FABMockApplicationIdentifierModel *appIDModel = [[FABMockApplicationIdentifierModel alloc] init];
4554
self.queue = [NSOperationQueue new];
46-
47-
self.fileManager = [[FIRCLSFileManager alloc] init];
55+
self.mockSettings = [[FIRCLSMockSettings alloc] initWithFileManager:self.fileManager
56+
appIDModel:appIDModel];
57+
self.mockSettings.fetchedBundleID = self.bundleIdentifier;
58+
self.networkClient = [[FIRCLSMockNetworkClient alloc] initWithQueue:self.queue
59+
fileManager:self.fileManager
60+
delegate:nil];
61+
self.fileManager = [[FIRCLSMockFileManager alloc] init];
4862
self.uploader = [[FIRCLSReportUploader alloc] initWithQueue:self.queue
4963
delegate:self
5064
dataSource:self
51-
client:nil
52-
fileManager:nil
65+
client:self.networkClient
66+
fileManager:self.fileManager
5367
analytics:nil];
54-
55-
// glue together a string that will work for both platforms
56-
NSString *urlString =
57-
[NSString stringWithFormat:@"%@/sdk-api/v1/platforms/%@/apps/%@/reports", TestEndpoint,
58-
FIRCLSApplicationGetPlatform(), self.bundleIdentifier];
59-
self.url = [NSURL URLWithString:urlString];
68+
self.mockDataTransport = [[FIRMockGDTCORTransport alloc] initWithMappingID:@"mappingID"
69+
transformers:nil
70+
target:1206];
6071
}
6172

6273
- (void)tearDown {
@@ -65,8 +76,153 @@ - (void)tearDown {
6576
[super tearDown];
6677
}
6778

79+
#pragma mark - Tests
80+
6881
- (void)testURLGeneration {
69-
XCTAssertEqualObjects([self.uploader reportURL], _url);
82+
NSString *urlString =
83+
[NSString stringWithFormat:@"%@/sdk-api/v1/platforms/%@/apps/%@/reports", TestEndpoint,
84+
FIRCLSApplicationGetPlatform(), self.bundleIdentifier];
85+
NSURL *url = [NSURL URLWithString:urlString];
86+
87+
XCTAssertEqualObjects([self.uploader reportURL], url);
88+
}
89+
90+
- (void)testPrepareReport {
91+
NSString *path = [self.fileManager.activePath stringByAppendingPathComponent:@"pkg_uuid"];
92+
FIRCLSInternalReport *report = [[FIRCLSInternalReport alloc] initWithPath:path];
93+
self.mockSettings.orgID = @"orgID";
94+
self.mockSettings.shouldUseNewReportEndpoint = YES;
95+
self.fileManager.moveItemAtPathResult = [NSNumber numberWithInt:1];
96+
97+
[self.uploader prepareAndSubmitReport:report
98+
dataCollectionToken:FIRCLSDataCollectionToken.validToken
99+
asUrgent:YES
100+
withProcessing:YES];
101+
102+
// Verify with the last move operation is from processing -> prepared
103+
XCTAssertTrue(
104+
[self.fileManager.moveItemAtPath_destDir containsString:self.fileManager.preparedPath]);
105+
}
106+
107+
- (void)testPrepareLegacyReport {
108+
NSString *path = [self.fileManager.activePath stringByAppendingPathComponent:@"pkg_uuid"];
109+
FIRCLSInternalReport *report = [[FIRCLSInternalReport alloc] initWithPath:path];
110+
self.mockSettings.orgID = @"orgID";
111+
self.mockSettings.shouldUseNewReportEndpoint = NO;
112+
self.fileManager.moveItemAtPathResult = [NSNumber numberWithInt:1];
113+
114+
[self.uploader prepareAndSubmitReport:report
115+
dataCollectionToken:FIRCLSDataCollectionToken.validToken
116+
asUrgent:YES
117+
withProcessing:YES];
118+
119+
// Verify with the last move operation is from active -> processing for the legacy workflow
120+
// FIRCLSPackageReportOperation will then move the report from processing -> prepared-legacy
121+
XCTAssertTrue(
122+
[self.fileManager.moveItemAtPath_destDir containsString:self.fileManager.processingPath]);
123+
}
124+
125+
- (void)testUploadPackagedReportWithPath {
126+
[self runUploadPackagedReportWithUrgency:NO];
127+
}
128+
129+
- (void)testUploadPackagedReportWithLegacyPath {
130+
[self runUploadPackagedReportLegacyWithUrgency:NO];
131+
}
132+
133+
- (void)testUrgentUploadPackagedReportWithPath {
134+
[self runUploadPackagedReportWithUrgency:YES];
135+
}
136+
137+
- (void)testUrgentUploadPackagedReportWithLegacyPath {
138+
[self runUploadPackagedReportLegacyWithUrgency:YES];
139+
}
140+
141+
- (void)testUploadPackagedReportWithMismatchPathAndSettings {
142+
[self setUpForLegacyUpload];
143+
144+
BOOL success = [self.uploader uploadPackagedReportAtPath:[self packagePath]
145+
dataCollectionToken:FIRCLSDataCollectionToken.validToken
146+
asUrgent:NO];
147+
XCTAssertFalse(success);
148+
XCTAssertNil(self.mockDataTransport.sendDataEvent_event);
149+
XCTAssertNil(self.networkClient.startUploadRequest);
150+
}
151+
152+
- (void)testUploadPackagedReportWithoutDataCollectionToken {
153+
[self setUpForUpload];
154+
155+
BOOL success = [self.uploader uploadPackagedReportAtPath:[self packagePath]
156+
dataCollectionToken:nil
157+
asUrgent:NO];
158+
XCTAssertFalse(success);
159+
XCTAssertNil(self.mockDataTransport.sendDataEvent_event);
160+
XCTAssertNil(self.networkClient.startUploadRequest);
161+
}
162+
163+
- (void)testUploadPackagedReportNotGDTWritten {
164+
[self setUpForUpload];
165+
self.mockDataTransport.sendDataEvent_wasWritten = NO;
166+
167+
[self.uploader uploadPackagedReportAtPath:[self packagePath] dataCollectionToken:nil asUrgent:NO];
168+
169+
// Did not delete report
170+
XCTAssertNil(self.fileManager.removedItemAtPath_path);
171+
}
172+
173+
- (void)testUploadPackagedReportGDTError {
174+
[self setUpForUpload];
175+
self.mockDataTransport.sendDataEvent_error = [[NSError alloc] initWithDomain:@"domain"
176+
code:1
177+
userInfo:nil];
178+
179+
[self.uploader uploadPackagedReportAtPath:[self packagePath] dataCollectionToken:nil asUrgent:NO];
180+
181+
// Did not delete report
182+
XCTAssertNil(self.fileManager.removedItemAtPath_path);
183+
}
184+
185+
#pragma mark - Helper functions
186+
187+
- (NSString *)packagePath {
188+
return [self.fileManager.preparedPath stringByAppendingPathComponent:@"pkg_uuid"];
189+
}
190+
191+
- (void)runUploadPackagedReportWithUrgency:(BOOL)urgent {
192+
[self setUpForUpload];
193+
194+
BOOL success = [self.uploader uploadPackagedReportAtPath:[self packagePath]
195+
dataCollectionToken:FIRCLSDataCollectionToken.validToken
196+
asUrgent:urgent];
197+
XCTAssertTrue(success);
198+
XCTAssertNotNil(self.mockDataTransport.sendDataEvent_event);
199+
XCTAssertNil(self.networkClient.startUploadRequest);
200+
XCTAssertEqualObjects(self.fileManager.removedItemAtPath_path, [self packagePath]);
201+
}
202+
203+
- (void)runUploadPackagedReportLegacyWithUrgency:(BOOL)urgent {
204+
NSString *packagePath =
205+
[self.fileManager.legacyPreparedPath stringByAppendingPathComponent:@"pkg_uuid"];
206+
207+
[self setUpForLegacyUpload];
208+
209+
BOOL success = [self.uploader uploadPackagedReportAtPath:packagePath
210+
dataCollectionToken:FIRCLSDataCollectionToken.validToken
211+
asUrgent:urgent];
212+
XCTAssertTrue(success);
213+
XCTAssertNil(self.mockDataTransport.sendDataEvent_event);
214+
XCTAssertNotNil(self.networkClient.startUploadRequest);
215+
}
216+
217+
- (void)setUpForUpload {
218+
self.mockSettings.shouldUseNewReportEndpoint = YES;
219+
self.mockDataTransport.sendDataEvent_wasWritten = YES;
220+
}
221+
222+
- (void)setUpForLegacyUpload {
223+
self.mockSettings.shouldUseNewReportEndpoint = NO;
224+
self.mockDataTransport.sendDataEvent_wasWritten = YES;
225+
self.fileManager.fileSizeAtPathResult = [NSNumber numberWithInt:1];
70226
}
71227

72228
#pragma mark - FIRCLSReportUploaderDelegate
@@ -76,6 +232,8 @@ - (void)didCompletePackageSubmission:(NSString *)path
76232
error:(NSError *)error {
77233
}
78234

235+
#pragma mark - FIRCLSReportUploaderDataSource
236+
79237
- (NSString *)bundleIdentifier {
80238
return @"com.test.TestApp";
81239
}
@@ -84,16 +242,12 @@ - (NSString *)googleAppID {
84242
return @"someGoogleAppId";
85243
}
86244

87-
- (FIRCLSSettings *)settings {
88-
FABMockApplicationIdentifierModel *appIDModel = [[FABMockApplicationIdentifierModel alloc] init];
89-
FIRCLSMockSettings *settings = [[FIRCLSMockSettings alloc] initWithFileManager:self.fileManager
90-
appIDModel:appIDModel];
91-
settings.fetchedBundleID = self.bundleIdentifier;
92-
return settings;
245+
- (GDTCORTransport *)googleTransport {
246+
return self.mockDataTransport;
93247
}
94248

95-
- (GDTCORTransport *)googleTransport {
96-
return [[FIRMockGDTCORTransport alloc] initWithMappingID:@"mappingID" transformers:nil target:0];
249+
- (FIRCLSSettings *)settings {
250+
return self.mockSettings;
97251
}
98252

99253
- (void)didCompleteAllSubmissions {

Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,25 @@
2626
// Incremented when a remove happens with removeItemAtPath
2727
@property(nonatomic) NSInteger removeCount;
2828

29+
// Overrides fileSizeAtPath if set
30+
@property(nonatomic, copy) NSNumber *fileSizeAtPathResult;
31+
2932
// Will be fulfilled when the expected number of removes have happened
3033
// using removeItemAtPath
3134
//
3235
// Users should initialize this in their test.
3336
@property(nonatomic, strong) XCTestExpectation *removeExpectation;
3437

38+
@property(nonatomic, copy) NSString *removedItemAtPath_path;
39+
3540
// Overriding the method for testing Settings
3641
- (BOOL)removeItemAtPath:(NSString *)path;
3742

43+
// Overrides moveItemAtPath if set
44+
@property(nonatomic) NSNumber *moveItemAtPathResult;
45+
@property(nonatomic, copy) NSString *moveItemAtPath_path;
46+
@property(nonatomic, copy) NSString *moveItemAtPath_destDir;
47+
48+
- (BOOL)moveItemAtPath:(NSString *)path toDirectory:(NSString *)destDir;
49+
3850
@end

Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ - (instancetype)init {
3131
}
3232

3333
- (BOOL)removeItemAtPath:(NSString *)path {
34+
self.removedItemAtPath_path = path;
35+
3436
[super removeItemAtPath:path];
3537

3638
self.removeCount += 1;
@@ -44,4 +46,23 @@ - (BOOL)removeItemAtPath:(NSString *)path {
4446
return YES;
4547
}
4648

49+
- (NSNumber *)fileSizeAtPath:(NSString *)path {
50+
if (self.fileSizeAtPathResult) {
51+
return self.fileSizeAtPathResult;
52+
}
53+
54+
return [super fileSizeAtPath:path];
55+
}
56+
57+
- (BOOL)moveItemAtPath:(NSString *)path toDirectory:(NSString *)destDir {
58+
self.moveItemAtPath_path = path;
59+
self.moveItemAtPath_destDir = destDir;
60+
61+
if (self.moveItemAtPathResult) {
62+
return self.moveItemAtPathResult.intValue > 0;
63+
}
64+
65+
return [super moveItemAtPath:path toDirectory:destDir];
66+
}
67+
4768
@end

Crashlytics/UnitTests/Mocks/FIRCLSMockNetworkClient.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616

1717
@interface FIRCLSMockNetworkClient : FIRCLSNetworkClient
1818

19+
@property(nonatomic, strong) NSURLRequest *startUploadRequest;
20+
1921
@end

Crashlytics/UnitTests/Mocks/FIRCLSMockNetworkClient.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ @implementation FIRCLSMockNetworkClient
1818

1919
- (void)startUploadRequest:(NSURLRequest *)request
2020
filePath:(NSString *)path
21+
dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
2122
immediately:(BOOL)immediate {
23+
self.startUploadRequest = request;
2224
NSLog(@"intercepted request");
2325
}
2426

Crashlytics/UnitTests/Mocks/FIRCLSMockSettings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818

1919
@property(nonatomic, copy) NSString* orgID;
2020
@property(nonatomic, copy) NSString* fetchedBundleID;
21+
@property(nonatomic) BOOL shouldUseNewReportEndpoint;
2122

2223
@end

Crashlytics/UnitTests/Mocks/FIRCLSMockSettings.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ @implementation FIRCLSMockSettings
2020
// and bypass the normal functionality
2121
@synthesize orgID;
2222
@synthesize fetchedBundleID;
23+
@synthesize shouldUseNewReportEndpoint;
2324

2425
@end

Crashlytics/UnitTests/Mocks/FIRMockGDTCoreTransport.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,18 @@
1616

1717
@interface FIRMockGDTCORTransport : GDTCORTransport
1818

19-
- (nullable instancetype)initWithMappingID:(NSString *_Nonnull)mappingID
20-
transformers:
21-
(nullable NSArray<id<GDTCOREventTransformer>> *)transformers
22-
target:(NSInteger)target NS_DESIGNATED_INITIALIZER;
19+
@property(nonatomic, copy) NSString *mappingID;
20+
@property(nonatomic) NSInteger target;
21+
22+
@property(nonatomic, strong) GDTCOREvent *sendDataEvent_event;
23+
@property(nonatomic, strong) NSError *sendDataEvent_error;
24+
@property(nonatomic) BOOL sendDataEvent_wasWritten;
25+
26+
- (instancetype)initWithMappingID:(NSString *)mappingID
27+
transformers:(NSArray<id<GDTCOREventTransformer>> *)transformers
28+
target:(NSInteger)target NS_DESIGNATED_INITIALIZER;
29+
30+
- (void)sendDataEvent:(GDTCOREvent *)event
31+
onComplete:(void (^)(BOOL wasWritten, NSError *error))completion;
2332

2433
@end

0 commit comments

Comments
 (0)