Skip to content

Commit b35b0de

Browse files
authored
Fix Catalyst Flaky Test (#9797)
1 parent 2eb177e commit b35b0de

File tree

8 files changed

+62
-22
lines changed

8 files changed

+62
-22
lines changed

Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ - (void)sendUnsentReportsWithToken:(FIRCLSDataCollectionToken *)dataCollectionTo
207207
// the file still exists.
208208
[self.operationQueue addOperationWithBlock:^{
209209
for (NSString *path in self.preparedReportPaths) {
210-
if (![[self.fileManager underlyingFileManager] fileExistsAtPath:path]) {
210+
if (![self.fileManager fileExistsAtPath:path]) {
211211
continue;
212212
}
213213
[self.reportUploader uploadPackagedReportAtPath:path

Crashlytics/Crashlytics/FIRCrashlytics.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ - (instancetype)initWithApp:(FIRApp *)app
131131
appIDModel:appModel];
132132

133133
FIRCLSOnDemandModel *onDemandModel =
134-
[[FIRCLSOnDemandModel alloc] initWithFIRCLSSettings:settings];
134+
[[FIRCLSOnDemandModel alloc] initWithFIRCLSSettings:settings fileManager:_fileManager];
135135
_managerData = [[FIRCLSManagerData alloc] initWithGoogleAppID:_googleAppID
136136
googleTransport:googleTransport
137137
installations:installations

Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.m

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#import "Crashlytics/Crashlytics/Handlers/FIRCLSException.h"
2121
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
2222
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
23+
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
2324
#import "Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.h"
2425
#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h"
2526

@@ -38,7 +39,7 @@ @interface FIRCLSOnDemandModel ()
3839
@property(nonatomic) double lastUpdated;
3940
@property(nonatomic) double currentStep;
4041

41-
@property(nonatomic, strong) NSFileManager *fileManager;
42+
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
4243
@property(nonatomic, strong) NSMutableArray *storedActiveReportPaths;
4344

4445
@end
@@ -52,13 +53,15 @@ @implementation FIRCLSOnDemandModel
5253
static const double MAX_DELAY_SEC = 3600;
5354
static const double SEC_PER_MINUTE = 60;
5455

55-
- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings {
56+
- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings
57+
fileManager:(FIRCLSFileManager *)fileManager {
5658
self = [super init];
5759
if (!self) {
5860
return nil;
5961
}
6062

6163
_settings = settings;
64+
_fileManager = fileManager;
6265

6366
NSString *sdkBundleID = FIRCLSApplicationGetSDKBundleID();
6467
_operationQueue = [NSOperationQueue new];
@@ -74,7 +77,6 @@ - (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings {
7477

7578
_lastUpdated = [NSDate timeIntervalSinceReferenceDate];
7679
_currentStep = -1;
77-
_fileManager = [[NSFileManager alloc] init];
7880

7981
self.storedActiveReportPaths = [NSMutableArray array];
8082

@@ -99,8 +101,7 @@ - (BOOL)recordOnDemandExceptionIfQuota:(FIRExceptionModel *)exceptionModel
99101
}
100102

101103
FIRCLSDataCollectionToken *dataCollectionToken = [FIRCLSDataCollectionToken validToken];
102-
NSString *activeReportPath = FIRCLSExceptionRecordOnDemandModel(
103-
exceptionModel, self.recordedOnDemandExceptionCount, self.droppedOnDemandExceptionCount);
104+
NSString *activeReportPath = [self recordOnDemandExceptionWithModel:exceptionModel];
104105

105106
if (!activeReportPath) {
106107
FIRCLSErrorLog(@"Error recording on-demand exception");
@@ -125,7 +126,7 @@ - (BOOL)recordOnDemandExceptionIfQuota:(FIRExceptionModel *)exceptionModel
125126
} else {
126127
[self.storedActiveReportPaths insertObject:activeReportPath atIndex:0];
127128
if ([self.storedActiveReportPaths count] > FIRCLSMaxUnsentReports) {
128-
[self.fileManager removeItemAtPath:[self.storedActiveReportPaths lastObject] error:nil];
129+
[self.fileManager removeItemAtPath:[self.storedActiveReportPaths lastObject]];
129130
[self.storedActiveReportPaths removeLastObject];
130131
[self decrementRecordedExceptionCount];
131132
[self incrementDroppedExceptionCount];
@@ -176,6 +177,11 @@ - (void)implementOnDemandUploadDelay:(int)delay {
176177
sleep(delay);
177178
}
178179

180+
- (NSString *)recordOnDemandExceptionWithModel:(FIRExceptionModel *)exceptionModel {
181+
return FIRCLSExceptionRecordOnDemandModel(exceptionModel, self.recordedOnDemandExceptionCount,
182+
self.droppedOnDemandExceptionCount);
183+
}
184+
179185
- (int)droppedOnDemandExceptionCount {
180186
@synchronized(self) {
181187
return _droppedOnDemandExceptionCount;

Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424

2525
@interface FIRCLSOnDemandModel (Private)
2626

27-
- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings;
27+
- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings
28+
fileManager:(FIRCLSFileManager *)fileManager;
2829

2930
- (BOOL)recordOnDemandExceptionIfQuota:(FIRExceptionModel *)exceptionModel
3031
withDataCollectionEnabled:(BOOL)dataCollectionEnabled

Crashlytics/UnitTests/FIRCLSOnDemandModelTests.m

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h"
2222
#import "Crashlytics/UnitTests/Mocks/FIRAppFake.h"
2323
#import "Crashlytics/UnitTests/Mocks/FIRCLSMockExistingReportManager.h"
24+
#import "Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.h"
2425
#import "Crashlytics/UnitTests/Mocks/FIRCLSMockOnDemandModel.h"
2526
#import "Crashlytics/UnitTests/Mocks/FIRCLSMockReportUploader.h"
2627
#import "Crashlytics/UnitTests/Mocks/FIRCLSMockSettings.h"
27-
#import "Crashlytics/UnitTests/Mocks/FIRCLSTempMockFileManager.h"
2828
#import "Crashlytics/UnitTests/Mocks/FIRMockGDTCoreTransport.h"
2929
#import "Crashlytics/UnitTests/Mocks/FIRMockInstallations.h"
3030

@@ -40,7 +40,7 @@ @interface FIRCLSOnDemandModelTests : XCTestCase
4040
@property(nonatomic, strong) FIRCLSExistingReportManager *existingReportManager;
4141
@property(nonatomic, strong) FIRCLSManagerData *managerData;
4242
@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter;
43-
@property(nonatomic, strong) FIRCLSTempMockFileManager *fileManager;
43+
@property(nonatomic, strong) FIRCLSMockFileManager *fileManager;
4444
@property(nonatomic, strong) FIRCLSMockReportUploader *mockReportUploader;
4545
@property(nonatomic, strong) FIRCLSMockSettings *mockSettings;
4646

@@ -57,12 +57,13 @@ - (void)setUp {
5757
id fakeApp = [[FIRAppFake alloc] init];
5858
self.dataArbiter = [[FIRCLSDataCollectionArbiter alloc] initWithApp:fakeApp withAppInfo:@{}];
5959

60-
self.fileManager = [[FIRCLSTempMockFileManager alloc] init];
60+
self.fileManager = [[FIRCLSMockFileManager alloc] init];
6161

6262
FIRCLSApplicationIdentifierModel *appIDModel = [[FIRCLSApplicationIdentifierModel alloc] init];
6363
_mockSettings = [[FIRCLSMockSettings alloc] initWithFileManager:self.fileManager
6464
appIDModel:appIDModel];
6565
_onDemandModel = [[FIRCLSMockOnDemandModel alloc] initWithFIRCLSSettings:_mockSettings
66+
fileManager:_fileManager
6667
sleepBlock:^(int delay){
6768
}];
6869

@@ -94,6 +95,7 @@ - (void)setUp {
9495
FIRCLSInternalReport *report =
9596
[[FIRCLSInternalReport alloc] initWithPath:reportPath
9697
executionIdentifier:@"TEST_EXECUTION_IDENTIFIER"];
98+
9799
FIRCLSContextInitialize(report, self.mockSettings, self.fileManager);
98100
}
99101

@@ -133,14 +135,14 @@ - (void)testIncrementsQueueWhenEventRecorded {
133135

134136
- (void)testCompliesWithDataCollectionOff {
135137
FIRExceptionModel *exceptionModel = [self getTestExceptionModel];
136-
XCTestExpectation *testComplete =
138+
XCTestExpectation *sleepComplete =
137139
[[XCTestExpectation alloc] initWithDescription:@"complete test"];
138140

139141
// Put an expectation in the sleep block so we can test the state of the queue.
140142
__weak FIRCLSOnDemandModelTests *weakSelf = self;
141143
[self setSleepBlock:^(int delay) {
142144
XCTAssertEqual(delay, 60 / self.mockSettings.onDemandUploadRate);
143-
[weakSelf waitForExpectations:@[ testComplete ] timeout:1.0];
145+
[weakSelf waitForExpectations:@[ sleepComplete ] timeout:1.0];
144146
}];
145147

146148
BOOL success = [self.onDemandModel recordOnDemandExceptionIfQuota:exceptionModel
@@ -149,14 +151,18 @@ - (void)testCompliesWithDataCollectionOff {
149151

150152
// Should record but not submit a report.
151153
XCTAssertTrue(success);
154+
152155
// We still count this as a recorded event if it was recorded but not submitted.
153156
XCTAssertEqual([self.onDemandModel recordedOnDemandExceptionCount], 1);
154-
XCTAssertEqual([self contentsOfActivePath].count, 2);
155157
XCTAssertEqual(self.onDemandModel.getQueuedOperationsCount, 1);
156-
XCTAssertEqual([self.onDemandModel.storedActiveReportPaths count], 1);
157158

158159
// Fulfill the expectation so the sleep block completes.
159-
[testComplete fulfill];
160+
[sleepComplete fulfill];
161+
[self.managerData.onDemandModel.operationQueue waitUntilAllOperationsAreFinished];
162+
163+
XCTAssertEqual(self.onDemandModel.getQueuedOperationsCount, 0);
164+
XCTAssertEqual([self contentsOfActivePath].count, 1);
165+
XCTAssertEqual([self.onDemandModel.storedActiveReportPaths count], 1);
160166
}
161167

162168
- (void)testQuotaWithDataCollectionOff {
@@ -179,7 +185,7 @@ - (void)testQuotaWithDataCollectionOff {
179185

180186
XCTAssertEqual([self.managerData.onDemandModel recordedOnDemandExceptionCount],
181187
FIRCLSMaxUnsentReports);
182-
XCTAssertEqual([self contentsOfActivePath].count, FIRCLSMaxUnsentReports + 1);
188+
XCTAssertEqual([self contentsOfActivePath].count, FIRCLSMaxUnsentReports);
183189
XCTAssertEqual([self.managerData.onDemandModel.storedActiveReportPaths count],
184190
FIRCLSMaxUnsentReports);
185191

@@ -188,7 +194,8 @@ - (void)testQuotaWithDataCollectionOff {
188194
asUrgent:YES];
189195
XCTAssertEqual([self.managerData.onDemandModel recordedOnDemandExceptionCount],
190196
FIRCLSMaxUnsentReports);
191-
XCTAssertEqual([self contentsOfActivePath].count, 1);
197+
[self.existingReportManager.operationQueue waitUntilAllOperationsAreFinished];
198+
XCTAssertEqual([self contentsOfActivePath].count, 0);
192199
XCTAssertEqual([self.managerData.onDemandModel.storedActiveReportPaths count], 0);
193200
}
194201

@@ -234,8 +241,7 @@ - (void)testDroppedEventCountResets {
234241

235242
#pragma mark - Helpers
236243
- (NSArray *)contentsOfActivePath {
237-
return [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.fileManager.activePath
238-
error:nil];
244+
return [self.fileManager activePathContents];
239245
}
240246

241247
- (FIRExceptionModel *)getTestExceptionModel {

Crashlytics/UnitTests/Mocks/FIRCLSMockFileManager.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ - (BOOL)createFileAtPath:(NSString *)path
5858
return YES;
5959
}
6060

61+
- (NSArray *)activePathContents {
62+
NSMutableArray *pathsWithActive = [[NSMutableArray alloc] init];
63+
for (NSString *path in [_fileSystemDict allKeys]) {
64+
if ([path containsString:@"v5/reports/active"]) {
65+
[pathsWithActive addObject:path];
66+
}
67+
}
68+
69+
return pathsWithActive;
70+
}
71+
6172
- (NSData *)dataWithContentsOfFile:(NSString *)path {
6273
return self.fileSystemDict[path];
6374
}

Crashlytics/UnitTests/Mocks/FIRCLSMockOnDemandModel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
@interface FIRCLSMockOnDemandModel : FIRCLSOnDemandModel
1919

2020
- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings
21+
fileManager:(FIRCLSFileManager *)fileManager
2122
sleepBlock:(void (^)(int))sleepBlock;
2223

2324
// Public for testing purposes

Crashlytics/UnitTests/Mocks/FIRCLSMockOnDemandModel.m

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,26 @@
1313
// limitations under the License.
1414

1515
#import "Crashlytics/UnitTests/Mocks/FIRCLSMockOnDemandModel.h"
16+
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
1617

1718
@interface FIRCLSMockOnDemandModel ()
1819

1920
@property(nonatomic, readonly) FIRCLSSettings *settings;
21+
@property(nonatomic, readonly) FIRCLSFileManager *fileManager;
2022

2123
@end
2224

2325
@implementation FIRCLSMockOnDemandModel
2426

2527
- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings
28+
fileManager:(FIRCLSFileManager *)fileManager
2629
sleepBlock:(void (^)(int))sleepBlock {
27-
self = [super initWithFIRCLSSettings:settings];
30+
self = [super initWithFIRCLSSettings:settings fileManager:fileManager];
2831
if (!self) {
2932
return nil;
3033
}
3134
_settings = settings;
35+
_fileManager = fileManager;
3236
_sleepBlock = sleepBlock;
3337
return self;
3438
}
@@ -48,4 +52,15 @@ - (void)implementOnDemandUploadDelay:(int)delay {
4852
_sleepBlock(delay);
4953
}
5054

55+
- (NSString *)recordOnDemandExceptionWithModel:(FIRExceptionModel *)exceptionModel {
56+
int randomSuffix = arc4random_uniform(10000);
57+
NSString *activePath = [_fileManager activePath];
58+
NSString *exceptionName =
59+
[activePath stringByAppendingPathComponent:[NSString stringWithFormat:@"test_exception_%d",
60+
randomSuffix]];
61+
NSData *data = [exceptionName dataUsingEncoding:NSUTF8StringEncoding];
62+
[self.fileManager createFileAtPath:exceptionName contents:data attributes:nil];
63+
return exceptionName;
64+
}
65+
5166
@end

0 commit comments

Comments
 (0)