Skip to content

Commit 25f626c

Browse files
FCM: async remove database in FIRMessagingRmqManager (#4771)
* Add tests for removeDatabase deadlock * Cleanup * Cleanup and comments. * FIRMessagingRmqManager: async remove database * FIRMessagingRmqManager: async remove DB test fixes. * Fix trailing spaces * Cleanup * FIR_MESSAGING_ASSERTIONS_BLOCKED handling added. FIR_MESSAGING_ASSERTIONS_BLOCKED is set in google3 tests * Fix blaze tests
1 parent a33111f commit 25f626c

16 files changed

+273
-10
lines changed

Example/Messaging/Tests/FIRInstanceIDWithFCMTest.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ - (void)setUp {
5454
}
5555

5656
- (void)tearDown {
57-
[_testUtil cleanupAfterTest];
57+
[_testUtil cleanupAfterTest:self];
5858
_instanceID = nil;
5959
_messaging = nil;
6060
[_mockFirebaseApp stopMocking];

Example/Messaging/Tests/FIRMessagingDataMessageManagerTest.m

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

1717
#import <OCMock/OCMock.h>
1818
#import <XCTest/XCTest.h>
19+
#import "XCTestCase+FIRMessagingRmqManagerTests.h"
1920

2021
#import <FirebaseMessaging/FIRMessaging.h>
2122

@@ -90,6 +91,7 @@ - (void)setUp {
9091
-(void)tearDown {
9192
if (_dataMessageManager.rmq2Manager) {
9293
[_dataMessageManager.rmq2Manager removeDatabase];
94+
[self waitForDrainDatabaseQueueForRmqManager:_dataMessageManager.rmq2Manager];
9395
}
9496
[super tearDown];
9597
}

Example/Messaging/Tests/FIRMessagingHandlingTest.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ - (void)setUp {
7676
}
7777

7878
- (void)tearDown {
79-
[_testUtil cleanupAfterTest];
79+
[_testUtil cleanupAfterTest:self];
8080
[_mockMessagingAnalytics stopMocking];
8181
[_mockFirebaseApp stopMocking];
8282
[super tearDown];

Example/Messaging/Tests/FIRMessagingLinkHandlingTest.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ - (void)setUp {
5353
}
5454

5555
- (void)tearDown {
56-
[_testUtil cleanupAfterTest];
56+
[_testUtil cleanupAfterTest:self];
5757
_messaging = nil;
5858
[[[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingTestsLinkHandlingSuiteName] removePersistentDomainForName:kFIRMessagingTestsLinkHandlingSuiteName];
5959
[super tearDown];

Example/Messaging/Tests/FIRMessagingRmqManagerTest.m

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
#import <XCTest/XCTest.h>
1818

19+
#import <OCMock/OCMock.h>
20+
21+
#import "FIRTestsAssertionHandler.h"
22+
#import "XCTestCase+FIRMessagingRmqManagerTests.h"
23+
1924
#import "Firebase/Messaging/FIRMessagingPersistentSyncMessage.h"
2025
#import "Firebase/Messaging/FIRMessagingRmqManager.h"
2126
#import "Firebase/Messaging/FIRMessagingUtilities.h"
@@ -28,26 +33,39 @@
2833
@interface FIRMessagingRmqManager (ExposedForTest)
2934

3035
- (void)removeDatabase;
36+
- (dispatch_queue_t)databaseOperationQueue;
3137

3238
@end
3339

3440
@interface FIRMessagingRmqManagerTest : XCTestCase
3541

3642
@property(nonatomic, readwrite, strong) FIRMessagingRmqManager *rmqManager;
43+
@property(nonatomic, strong) id assertionHandlerMock;
44+
@property(nonatomic, strong) FIRTestsAssertionHandler *testAssertionHandler;
3745

3846
@end
3947

4048
@implementation FIRMessagingRmqManagerTest
4149

4250
- (void)setUp {
4351
[super setUp];
52+
53+
self.testAssertionHandler = [[FIRTestsAssertionHandler alloc] init];
54+
self.assertionHandlerMock = OCMClassMock([NSAssertionHandler class]);
55+
OCMStub([self.assertionHandlerMock currentHandler]).andReturn(self.testAssertionHandler);
56+
4457
// Make sure we start off with a clean state each time
4558
_rmqManager = [[FIRMessagingRmqManager alloc] initWithDatabaseName:kRmqDatabaseName];
46-
4759
}
4860

4961
- (void)tearDown {
5062
[self.rmqManager removeDatabase];
63+
[self waitForDrainDatabaseQueueForRmqManager:self.rmqManager];
64+
65+
[self.assertionHandlerMock stopMocking];
66+
self.assertionHandlerMock = nil;
67+
self.testAssertionHandler = nil;
68+
5169
[super tearDown];
5270
}
5371

@@ -302,6 +320,40 @@ - (void)testDeleteSyncMessage {
302320
XCTAssertNil([self.rmqManager querySyncMessageWithRmqID:rmqID]);
303321
}
304322

323+
- (void)testInitWhenDatabaseIsBrokenThenDatabaseIsDeleted {
324+
NSString *databaseName = @"invalid-database-file";
325+
NSString *databasePath = [self createBrokenDatabaseWithName:databaseName];
326+
XCTAssert([[NSFileManager defaultManager] fileExistsAtPath:databasePath]);
327+
328+
// Expect for at least one assertion.
329+
XCTestExpectation *assertionFailureExpectation = [self expectationWithDescription:@"assertionFailureExpectation"];
330+
assertionFailureExpectation.assertForOverFulfill = NO;
331+
332+
// The flag FIR_MESSAGING_ASSERTIONS_BLOCKED can be set by blaze when running tests from google3.
333+
#ifndef FIR_MESSAGING_ASSERTIONS_BLOCKED
334+
[self.testAssertionHandler setMethodFailureHandlerForClass:[FIRMessagingRmqManager class]
335+
handler:^(id object, NSString *fileName, NSInteger lineNumber) {
336+
[assertionFailureExpectation fulfill];
337+
}];
338+
#else
339+
// If FIR_MESSAGING_ASSERTIONS_BLOCKED is defined, then no assertion handlers will be called,
340+
// so don't wait for it.
341+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
342+
[assertionFailureExpectation fulfill];
343+
});
344+
#endif // FIR_MESSAGING_ASSERTIONS_BLOCKED
345+
346+
// Create `FIRMessagingRmqManager` instance with a broken database.
347+
FIRMessagingRmqManager *manager = [[FIRMessagingRmqManager alloc] initWithDatabaseName:databaseName];
348+
349+
[self waitForExpectations:@[ assertionFailureExpectation ] timeout:0.5];
350+
351+
[self waitForDrainDatabaseQueueForRmqManager:manager];
352+
353+
// Check that the file was deleted.
354+
XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:databasePath]);
355+
}
356+
305357
#pragma mark - Private Helpers
306358

307359
- (GtalkDataMessageStanza *)dataMessageWithMessageID:(NSString *)messageID
@@ -323,4 +375,24 @@ - (GtalkDataMessageStanza *)dataMessageWithMessageID:(NSString *)messageID
323375
return stanza;
324376
}
325377

378+
- (NSString *)createBrokenDatabaseWithName:(NSString *)name {
379+
NSString *databasePath = [FIRMessagingRmqManager pathForDatabaseWithName:name];
380+
NSMutableArray *pathComponents = [[databasePath pathComponents] mutableCopy];
381+
[pathComponents removeLastObject];
382+
NSString *directoryPath = [NSString pathWithComponents:pathComponents];
383+
384+
// Create directory if doesn't exist.
385+
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:NULL];
386+
// Remove the file if exists.
387+
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
388+
389+
NSData *brokenDBFileContent = [@"not a valid DB" dataUsingEncoding:NSUTF8StringEncoding];
390+
[brokenDBFileContent writeToFile:databasePath atomically:YES];
391+
392+
XCTAssertEqualObjects([NSData dataWithContentsOfFile:databasePath], brokenDBFileContent);
393+
return databasePath;
394+
}
395+
396+
397+
326398
@end

Example/Messaging/Tests/FIRMessagingServiceTest.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ - (void)setUp {
8585
}
8686

8787
- (void)tearDown {
88-
[_testUtil cleanupAfterTest];
88+
[_testUtil cleanupAfterTest:self];
8989
_messaging = nil;
9090
[_mockPubSub stopMocking];
9191
[[[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingTestsServiceSuiteName] removePersistentDomainForName:kFIRMessagingTestsServiceSuiteName];

Example/Messaging/Tests/FIRMessagingSyncMessageManagerTest.m

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

1717
#import <XCTest/XCTest.h>
1818

19+
#import "XCTestCase+FIRMessagingRmqManagerTests.h"
20+
1921
#import "Firebase/Messaging/FIRMessagingPersistentSyncMessage.h"
2022
#import "Firebase/Messaging/FIRMessagingRmqManager.h"
2123
#import "Firebase/Messaging/FIRMessagingSyncMessageManager.h"
@@ -48,6 +50,7 @@ - (void)setUp {
4850

4951
- (void)tearDown {
5052
[_rmqManager removeDatabase];
53+
[self waitForDrainDatabaseQueueForRmqManager:_rmqManager];
5154
[super tearDown];
5255
}
5356

Example/Messaging/Tests/FIRMessagingTest.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ - (void)setUp {
8282
}
8383

8484
- (void)tearDown {
85-
[_testUtil cleanupAfterTest];
85+
[_testUtil cleanupAfterTest:self];
8686
[_mockFirebaseApp stopMocking];
8787
_messaging = nil;
8888
[[[NSUserDefaults alloc] initWithSuiteName:kFIRMessagingDefaultsTestDomain]

Example/Messaging/Tests/FIRMessagingTestUtilities.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
4141

4242
- (instancetype)initWithUserDefaults:(NSUserDefaults *)userDefaults withRMQManager:(BOOL)withRMQManager;
4343

44-
- (void)cleanupAfterTest;
44+
- (void)cleanupAfterTest:(XCTestCase *)testCase;
4545

4646
@end
4747

Example/Messaging/Tests/FIRMessagingTestUtilities.m

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#import <OCMock/OCMock.h>
1818

19+
#import "XCTestCase+FIRMessagingRmqManagerTests.h"
20+
1921
#import "Example/Messaging/Tests/FIRMessagingTestUtilities.h"
2022

2123
#import <FirebaseAnalyticsInterop/FIRAnalyticsInterop.h>
@@ -95,8 +97,9 @@ - (instancetype)initWithUserDefaults:(GULUserDefaults *)userDefaults withRMQMana
9597
return self;
9698
}
9799

98-
- (void)cleanupAfterTest {
100+
- (void)cleanupAfterTest:(XCTestCase *)testCase {
99101
[_messaging.rmq2Manager removeDatabase];
102+
[testCase waitForDrainDatabaseQueueForRmqManager:_messaging.rmq2Manager];
100103
[_messaging.messagingUserDefaults removePersistentDomainForName:kFIRMessagingDefaultsTestDomain];
101104
_messaging.shouldEstablishDirectChannel = NO;
102105
[_mockPubsub stopMocking];

0 commit comments

Comments
 (0)