diff --git a/Example/Database/Tests/Helpers/FDevice.h b/Example/Database/Tests/Helpers/FDevice.h index 503eacc7c52..c32aea0c833 100644 --- a/Example/Database/Tests/Helpers/FDevice.h +++ b/Example/Database/Tests/Helpers/FDevice.h @@ -18,7 +18,6 @@ @class FIRDatabaseReference; @class SenTest; -@class XCTest; @interface FDevice : NSObject - (id)initOnline; diff --git a/Example/Database/Tests/Helpers/FDevice.m b/Example/Database/Tests/Helpers/FDevice.m index 92403416442..f67502a5fde 100644 --- a/Example/Database/Tests/Helpers/FDevice.m +++ b/Example/Database/Tests/Helpers/FDevice.m @@ -58,7 +58,7 @@ - (id)initOfflineWithUrl:(NSString *)firebaseUrl { - (id)initWithUrl:(NSString *)firebaseUrl andOnline:(BOOL)online { self = [super init]; if (self) { - config = [FTestHelpers configForName:[NSString stringWithFormat:@"device-%lu", deviceId++]]; + config = [FIRDatabaseConfig configForName:[NSString stringWithFormat:@"device-%lu", deviceId++]]; config.persistenceEnabled = YES; url = firebaseUrl; isOnline = online; diff --git a/Example/Database/Tests/Helpers/FIRFakeApp.h b/Example/Database/Tests/Helpers/FIRFakeApp.h index 0f9339fad14..afe976a63b0 100644 --- a/Example/Database/Tests/Helpers/FIRFakeApp.h +++ b/Example/Database/Tests/Helpers/FIRFakeApp.h @@ -16,7 +16,6 @@ #import -@class FIRComponentContainer; @class FIRFakeOptions; @interface FIRFakeApp : NSObject @@ -25,5 +24,4 @@ @property(nonatomic, readonly) FIRFakeOptions *options; @property(nonatomic, copy, readonly) NSString *name; -@property(nonatomic, readonly) FIRComponentContainer *container; @end diff --git a/Example/Database/Tests/Helpers/FIRFakeApp.m b/Example/Database/Tests/Helpers/FIRFakeApp.m index c1a3695a296..b7abe81aadb 100644 --- a/Example/Database/Tests/Helpers/FIRFakeApp.m +++ b/Example/Database/Tests/Helpers/FIRFakeApp.m @@ -16,49 +16,33 @@ #import "FIRFakeApp.h" -#import "FIRAuthInteropFake.h" -#import "FIRComponentTestUtilities.h" -#import "FIRDatabaseComponent.h" - @interface FIRFakeOptions: NSObject @property(nonatomic, readonly, copy) NSString *databaseURL; -- (instancetype)initWithURL:(NSString *)url; +- (instancetype) initWithURL:(NSString *)url; @end @implementation FIRFakeOptions -- (instancetype)initWithURL:(NSString *)url { - self = [super init]; - if (self) { - _databaseURL = url; - } - return self; +- (instancetype) initWithURL:(NSString *)url { + self = [super init]; + if (self) { + self->_databaseURL = url; + } + return self; } @end -@interface FIRDatabaseComponent (Internal) -- (instancetype)initWithApp:(FIRApp *)app; -@end - @implementation FIRFakeApp -- (instancetype)initWithName:(NSString *)name URL:(NSString *)url { - self = [super init]; - if (self) { - _name = name; - _options = [[FIRFakeOptions alloc] initWithURL:url]; - _Nullable id (^authBlock)(FIRComponentContainer *, BOOL *) = - ^(FIRComponentContainer *container, BOOL *isCacheable) { - return [[FIRAuthInteropFake alloc] initWithToken:nil userID:nil error:nil]; - }; - FIRComponentCreationBlock databaseBlock = - ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { - return [[FIRDatabaseComponent alloc] initWithApp:container.app]; - }; - NSDictionary *components = - @{NSStringFromProtocol(@protocol(FIRAuthInterop)) : authBlock, - NSStringFromProtocol(@protocol(FIRDatabaseProvider)) : databaseBlock}; - _container = [[FIRComponentContainer alloc] initWithApp:(FIRApp *)self components:components]; - } - return self; +- (instancetype) initWithName:(NSString *)name URL:(NSString *)url { + self = [super init]; + if (self) { + self->_name = name; + self->_options = [[FIRFakeOptions alloc] initWithURL:url]; + } + return self; +} + +- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(void (^)(NSString *_Nullable token, NSError *_Nullable error))callback { + callback(nil, nil); } @end diff --git a/Example/Database/Tests/Helpers/FTestHelpers.h b/Example/Database/Tests/Helpers/FTestHelpers.h index a3f43876a4d..679be7ee663 100644 --- a/Example/Database/Tests/Helpers/FTestHelpers.h +++ b/Example/Database/Tests/Helpers/FTestHelpers.h @@ -28,8 +28,6 @@ #define PATH(__path) [FPath pathWithString:(__path)] @interface FTestHelpers : XCTestCase -+ (FIRDatabaseConfig *) defaultConfig; -+ (FIRDatabaseConfig *) configForName:(NSString *)name; + (FIRDatabaseReference *) getRandomNode; + (FIRDatabaseReference *) getRandomNodeWithoutPersistence; + (FTupleFirebase *) getRandomNodePair; diff --git a/Example/Database/Tests/Helpers/FTestHelpers.m b/Example/Database/Tests/Helpers/FTestHelpers.m index da2b546e3b4..35f85f08708 100644 --- a/Example/Database/Tests/Helpers/FTestHelpers.m +++ b/Example/Database/Tests/Helpers/FTestHelpers.m @@ -15,141 +15,118 @@ */ #import "FTestHelpers.h" - -#import -#import -#import -#import -#import - #import "FConstants.h" -#import "FIRAuthInteropFake.h" +#import +#import #import "FIRDatabaseConfig_Private.h" #import "FTestAuthTokenGenerator.h" @implementation FTestHelpers -+ (NSTimeInterval)waitUntil:(BOOL (^)())predicate timeout:(NSTimeInterval)seconds { - NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate]; - NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:seconds]; - NSTimeInterval timeoutTime = [timeoutDate timeIntervalSinceReferenceDate]; - NSTimeInterval currentTime; - - for (currentTime = [NSDate timeIntervalSinceReferenceDate]; - !predicate() && currentTime < timeoutTime; - currentTime = [NSDate timeIntervalSinceReferenceDate]) { - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode - beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; - } ++ (NSTimeInterval) waitUntil:(BOOL (^)())predicate timeout:(NSTimeInterval)seconds { + NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate]; + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:seconds]; + NSTimeInterval timeoutTime = [timeoutDate timeIntervalSinceReferenceDate]; + NSTimeInterval currentTime; - NSTimeInterval finish = [NSDate timeIntervalSinceReferenceDate]; + for (currentTime = [NSDate timeIntervalSinceReferenceDate]; + !predicate() && currentTime < timeoutTime; + currentTime = [NSDate timeIntervalSinceReferenceDate]) { + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.25]]; + } - NSAssert(currentTime <= timeoutTime, @"Timed out"); + NSTimeInterval finish = [NSDate timeIntervalSinceReferenceDate]; - return (finish - start); -} + NSAssert(currentTime <= timeoutTime, @"Timed out"); -+ (FIRDatabaseConfig *)defaultConfig { - return [self configForName:@"default"]; + return (finish - start); } -+ (FIRDatabaseConfig *)configForName:(NSString *)name { - id auth = [[FIRAuthInteropFake alloc] initWithToken:nil userID:nil error:nil]; - id authTokenProvider = [FAuthTokenProvider authTokenProviderWithAuth:auth]; - return [[FIRDatabaseConfig alloc] initWithSessionIdentifier:name - authTokenProvider:authTokenProvider]; -} ++ (NSArray*) getRandomNodes:(int)num persistence:(BOOL)persistence { + static dispatch_once_t pred = 0; + static NSMutableArray *persistenceRefs = nil; + static NSMutableArray *noPersistenceRefs = nil; + dispatch_once(&pred, ^{ + persistenceRefs = [[NSMutableArray alloc] init]; + noPersistenceRefs = [[NSMutableArray alloc] init]; + // Uncomment the following line to run tests against a background thread + //[Firebase setDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; + }); + + NSMutableArray *refs = (persistence) ? persistenceRefs : noPersistenceRefs; + + id authTokenProvider = [FAuthTokenProvider authTokenProviderForApp:[FIRApp defaultApp]]; + + while (num > refs.count) { + NSString *sessionIdentifier = [NSString stringWithFormat:@"test-config-%@persistence-%lu", (persistence) ? @"" : @"no-", refs.count]; + FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc] initWithSessionIdentifier:sessionIdentifier authTokenProvider:authTokenProvider]; + config.persistenceEnabled = persistence; + FIRDatabaseReference * ref = [[FIRDatabaseReference alloc] initWithConfig:config]; + [refs addObject:ref]; + } -+ (NSArray *)getRandomNodes:(int)num persistence:(BOOL)persistence { - static dispatch_once_t pred = 0; - static NSMutableArray *persistenceRefs = nil; - static NSMutableArray *noPersistenceRefs = nil; - dispatch_once(&pred, ^{ - persistenceRefs = [[NSMutableArray alloc] init]; - noPersistenceRefs = [[NSMutableArray alloc] init]; - // Uncomment the following line to run tests against a background thread - //[Firebase setDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; - }); - - NSMutableArray *refs = (persistence) ? persistenceRefs : noPersistenceRefs; - - id auth = [[FIRAuthInteropFake alloc] initWithToken:nil userID:nil error:nil]; - id authTokenProvider = [FAuthTokenProvider authTokenProviderWithAuth:auth]; - - while (num > refs.count) { - NSString *sessionIdentifier = - [NSString stringWithFormat:@"test-config-%@persistence-%lu", (persistence) ? @"" : @"no-", - refs.count]; - FIRDatabaseConfig *config = - [[FIRDatabaseConfig alloc] initWithSessionIdentifier:sessionIdentifier - authTokenProvider:authTokenProvider]; - config.persistenceEnabled = persistence; - FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] initWithConfig:config]; - [refs addObject:ref]; - } - - NSMutableArray *results = [[NSMutableArray alloc] init]; - NSString *name = nil; - for (int i = 0; i < num; ++i) { - FIRDatabaseReference *ref = [refs objectAtIndex:i]; - if (!name) { - name = [ref childByAutoId].key; + NSMutableArray* results = [[NSMutableArray alloc] init]; + NSString* name = nil; + for (int i = 0; i < num; ++i) { + FIRDatabaseReference * ref = [refs objectAtIndex:i]; + if (!name) { + name = [ref childByAutoId].key; + } + [results addObject:[ref child:name]]; } - [results addObject:[ref child:name]]; - } - return results; + return results; } // Helpers -+ (FIRDatabaseReference *)getRandomNode { - NSArray *refs = [self getRandomNodes:1 persistence:YES]; - return [refs objectAtIndex:0]; ++ (FIRDatabaseReference *) getRandomNode { + NSArray* refs = [self getRandomNodes:1 persistence:YES]; + return [refs objectAtIndex:0]; } -+ (FIRDatabaseReference *)getRandomNodeWithoutPersistence { - NSArray *refs = [self getRandomNodes:1 persistence:NO]; - return refs[0]; ++ (FIRDatabaseReference *) getRandomNodeWithoutPersistence { + NSArray* refs = [self getRandomNodes:1 persistence:NO]; + return refs[0]; } -+ (FTupleFirebase *)getRandomNodePair { - NSArray *refs = [self getRandomNodes:2 persistence:YES]; ++ (FTupleFirebase *) getRandomNodePair { + NSArray* refs = [self getRandomNodes:2 persistence:YES]; - FTupleFirebase *tuple = [[FTupleFirebase alloc] init]; - tuple.one = [refs objectAtIndex:0]; - tuple.two = [refs objectAtIndex:1]; + FTupleFirebase* tuple = [[FTupleFirebase alloc] init]; + tuple.one = [refs objectAtIndex:0]; + tuple.two = [refs objectAtIndex:1]; - return tuple; + return tuple; } -+ (FTupleFirebase *)getRandomNodePairWithoutPersistence { - NSArray *refs = [self getRandomNodes:2 persistence:NO]; ++ (FTupleFirebase *) getRandomNodePairWithoutPersistence { + NSArray* refs = [self getRandomNodes:2 persistence:NO]; - FTupleFirebase *tuple = [[FTupleFirebase alloc] init]; - tuple.one = refs[0]; - tuple.two = refs[1]; + FTupleFirebase* tuple = [[FTupleFirebase alloc] init]; + tuple.one = refs[0]; + tuple.two = refs[1]; - return tuple; + return tuple; } -+ (FTupleFirebase *)getRandomNodeTriple { - NSArray *refs = [self getRandomNodes:3 persistence:YES]; - FTupleFirebase *triple = [[FTupleFirebase alloc] init]; - triple.one = [refs objectAtIndex:0]; - triple.two = [refs objectAtIndex:1]; - triple.three = [refs objectAtIndex:2]; ++ (FTupleFirebase *) getRandomNodeTriple { + NSArray* refs = [self getRandomNodes:3 persistence:YES]; + FTupleFirebase* triple = [[FTupleFirebase alloc] init]; + triple.one = [refs objectAtIndex:0]; + triple.two = [refs objectAtIndex:1]; + triple.three = [refs objectAtIndex:2]; - return triple; + return triple; } + (id)leafNodeOfSize:(NSUInteger)size { - NSMutableString *string = [NSMutableString string]; - NSString *pattern = @"abdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - for (NSUInteger i = 0; i < size - pattern.length; i = i + pattern.length) { - [string appendString:pattern]; - } - NSUInteger remainingLength = size - string.length; - [string appendString:[pattern substringToIndex:remainingLength]]; - return [FSnapshotUtilities nodeFrom:string]; + NSMutableString *string = [NSMutableString string]; + NSString *pattern = @"abdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + for (NSUInteger i = 0; i < size - pattern.length; i = i + pattern.length) { + [string appendString:pattern]; + } + NSUInteger remainingLength = size - string.length; + [string appendString:[pattern substringToIndex:remainingLength]]; + return [FSnapshotUtilities nodeFrom:string]; } @end diff --git a/Example/Database/Tests/Integration/FData.m b/Example/Database/Tests/Integration/FData.m index 00bd511d646..89b109036b3 100644 --- a/Example/Database/Tests/Integration/FData.m +++ b/Example/Database/Tests/Integration/FData.m @@ -2529,7 +2529,7 @@ - (void) testUpdateAfterChildSet { - (void) testDeltaSyncNoDataUpdatesAfterReconnect { FIRDatabaseReference *ref = [FTestHelpers getRandomNode]; - FIRDatabaseConfig *cfg = [FTestHelpers configForName:@"test-config"]; + FIRDatabaseConfig *cfg = [FIRDatabaseConfig configForName:@"test-config"]; FIRDatabaseReference * ref2 = [[[FIRDatabaseReference alloc] initWithConfig:cfg] child:ref.key]; __block id data = @{ @"a": @1, @"b": @2, @"c": @{ @".priority": @3, @".value": @3}, @"d": @4 }; [self waitForCompletionOf:ref setValue:data]; diff --git a/Example/Database/Tests/Integration/FDotInfo.m b/Example/Database/Tests/Integration/FDotInfo.m index 0df3d319442..60869ce7c28 100644 --- a/Example/Database/Tests/Integration/FDotInfo.m +++ b/Example/Database/Tests/Integration/FDotInfo.m @@ -51,7 +51,7 @@ - (void) testCanWatchInfoConnected { } - (void) testInfoConnectedGoesToFalseOnDisconnect { - FIRDatabaseConfig *cfg = [FTestHelpers configForName:@"test-config"]; + FIRDatabaseConfig *cfg = [FIRDatabaseConfig configForName:@"test-config"]; FIRDatabaseReference * rootRef = [[FIRDatabaseReference alloc] initWithConfig:cfg]; __block BOOL everConnected = NO; __block NSMutableString *connectedHistory = [[NSMutableString alloc] init]; @@ -78,7 +78,7 @@ - (void) testInfoConnectedGoesToFalseOnDisconnect { } - (void) testInfoServerTimeOffset { - FIRDatabaseConfig *cfg = [FTestHelpers configForName:@"test-config"]; + FIRDatabaseConfig *cfg = [FIRDatabaseConfig configForName:@"test-config"]; FIRDatabaseReference * ref = [[FIRDatabaseReference alloc] initWithConfig:cfg]; // make sure childByAutoId works @@ -103,8 +103,8 @@ - (void) testInfoServerTimeOffset { } - (void) testManualConnectionManagement { - FIRDatabaseConfig *cfg = [FTestHelpers configForName:@"test-config"]; - FIRDatabaseConfig *altCfg = [FTestHelpers configForName:@"alt-config"]; + FIRDatabaseConfig *cfg = [FIRDatabaseConfig configForName:@"test-config"]; + FIRDatabaseConfig *altCfg = [FIRDatabaseConfig configForName:@"alt-config"]; FIRDatabaseReference * ref = [[FIRDatabaseReference alloc] initWithConfig:cfg]; FIRDatabaseReference * refAlt = [[FIRDatabaseReference alloc] initWithConfig:altCfg]; diff --git a/Example/Database/Tests/Integration/FIRAuthTests.m b/Example/Database/Tests/Integration/FIRAuthTests.m index 75f2364af18..e520c84a20d 100644 --- a/Example/Database/Tests/Integration/FIRAuthTests.m +++ b/Example/Database/Tests/Integration/FIRAuthTests.m @@ -16,17 +16,13 @@ #import -#import -#import -#import -#import +#import -#import "FIRAuthInteropFake.h" -#import "FIRDatabaseConfig_Private.h" -#import "FIRTestAuthTokenProvider.h" +#import "FTestHelpers.h" #import "FTestAuthTokenGenerator.h" +#import "FIRTestAuthTokenProvider.h" +#import "FIRDatabaseConfig_Private.h" #import "FTestBase.h" -#import "FTestHelpers.h" @interface FIRAuthTests : FTestBase @@ -35,43 +31,39 @@ @interface FIRAuthTests : FTestBase @implementation FIRAuthTests - (void)setUp { - [super setUp]; + [super setUp]; } - (void)tearDown { - [super tearDown]; + [super tearDown]; } - (void)testListensAndAuthRaceCondition { - [FIRDatabase setLoggingEnabled:YES]; - FIRAuthInteropFake *auth = [[FIRAuthInteropFake alloc] initWithToken:nil userID:nil error:nil]; - id authTokenProvider = [FAuthTokenProvider authTokenProviderWithAuth:auth]; + [FIRDatabase setLoggingEnabled:YES]; + id tokenProvider = [FAuthTokenProvider authTokenProviderForApp:[FIRApp defaultApp]]; - FIRDatabaseConfig *config = [FTestHelpers configForName:@"testWritesRestoredAfterAuth"]; - config.authTokenProvider = authTokenProvider; + FIRDatabaseConfig *config = [FIRDatabaseConfig configForName:@"testWritesRestoredAfterAuth"]; + config.authTokenProvider = tokenProvider; - FIRDatabaseReference *ref = [[[FIRDatabaseReference alloc] initWithConfig:config] childByAutoId]; + FIRDatabaseReference *ref = [[[FIRDatabaseReference alloc] initWithConfig:config] childByAutoId]; - __block BOOL done = NO; + __block BOOL done = NO; - [[[ref root] child:@".info/connected"] - observeEventType:FIRDataEventTypeValue - withBlock:^void(FIRDataSnapshot *snapshot) { - if ([snapshot.value boolValue]) { - // Start a listen before auth credentials are restored. - [ref observeEventType:FIRDataEventTypeValue - withBlock:^(FIRDataSnapshot *snapshot){ + [[[ref root] child:@".info/connected"] observeEventType:FIRDataEventTypeValue withBlock:^void( + FIRDataSnapshot *snapshot) { + if ([snapshot.value boolValue]) { + // Start a listen before auth credentials are restored. + [ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { - }]; + }]; - // subsequent writes should complete successfully. - [ref setValue:@42 - withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) { - done = YES; - }]; - } - }]; + // subsequent writes should complete successfully. + [ref setValue:@42 withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) { + done = YES; + }]; + } + }]; - WAIT_FOR(done); + WAIT_FOR(done); } @end diff --git a/Example/Database/Tests/Integration/FIRDatabaseTests.m b/Example/Database/Tests/Integration/FIRDatabaseTests.m index ed25be5dfff..8a988242d52 100644 --- a/Example/Database/Tests/Integration/FIRDatabaseTests.m +++ b/Example/Database/Tests/Integration/FIRDatabaseTests.m @@ -183,7 +183,7 @@ - (void) testReferenceEqualityForFIRDatabase { } - (FIRDatabaseReference *)rootRefWithEngine:(id)engine name:(NSString *)name { - FIRDatabaseConfig *config = [FTestHelpers configForName:name]; + FIRDatabaseConfig *config = [FIRDatabaseConfig configForName:name]; config.persistenceEnabled = YES; config.forceStorageEngine = engine; return [[FIRDatabaseReference alloc] initWithConfig:config]; diff --git a/Example/Database/Tests/Integration/FRealtime.m b/Example/Database/Tests/Integration/FRealtime.m index 62ce85103ff..5acda07e98e 100644 --- a/Example/Database/Tests/Integration/FRealtime.m +++ b/Example/Database/Tests/Integration/FRealtime.m @@ -20,7 +20,6 @@ #import "FUtilities.h" #import "FParsedUrl.h" #import "FIRDatabaseConfig_Private.h" -#import "FTestHelpers.h" @implementation FRealtime @@ -77,8 +76,8 @@ - (void) testCachingRedirects { } - (void) testOnDisconnectSetWorks { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; - FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; + FIRDatabaseConfig *readerCfg = [FIRDatabaseConfig configForName:@"reader"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key]; @@ -135,8 +134,8 @@ - (void) testOnDisconnectSetWorks { } - (void) testOnDisconnectSetWithPriorityWorks { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; - FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; + FIRDatabaseConfig *readerCfg = [FIRDatabaseConfig configForName:@"reader"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key]; @@ -182,8 +181,8 @@ - (void) testOnDisconnectSetWithPriorityWorks { } - (void) testOnDisconnectRemoveWorks { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; - FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; + FIRDatabaseConfig *readerCfg = [FIRDatabaseConfig configForName:@"reader"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key]; @@ -229,8 +228,8 @@ - (void) testOnDisconnectRemoveWorks { } - (void) testOnDisconnectUpdateWorks { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; - FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; + FIRDatabaseConfig *readerCfg = [FIRDatabaseConfig configForName:@"reader"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key]; @@ -276,7 +275,7 @@ - (void) testOnDisconnectUpdateWorks { } - (void) testOnDisconnectTriggersSingleLocalValueEventForWriter { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; __block int calls = 0; @@ -319,7 +318,7 @@ - (void) testOnDisconnectTriggersSingleLocalValueEventForWriter { } - (void) testOnDisconnectTriggersSingleLocalValueEventForReader { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; FIRDatabaseReference * reader = [FTestHelpers getRandomNode]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] child:reader.key]; @@ -363,7 +362,7 @@ - (void) testOnDisconnectTriggersSingleLocalValueEventForReader { } - (void) testOnDisconnectTriggersSingleLocalValueEventForWriterWithQuery { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; __block int calls = 0; @@ -407,7 +406,7 @@ - (void) testOnDisconnectTriggersSingleLocalValueEventForWriterWithQuery { - (void) testOnDisconnectTriggersSingleLocalValueEventForReaderWithQuery { FIRDatabaseReference * reader = [FTestHelpers getRandomNode]; - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] child:reader.key]; __block int calls = 0; @@ -452,7 +451,7 @@ - (void) testOnDisconnectTriggersSingleLocalValueEventForReaderWithQuery { - (void) testOnDisconnectDeepMergeTriggersOnlyOneValueEventForReaderWithQuery { FIRDatabaseReference * reader = [FTestHelpers getRandomNode]; - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; __block BOOL done = NO; @@ -488,8 +487,8 @@ - (void) testOnDisconnectDeepMergeTriggersOnlyOneValueEventForReaderWithQuery { - (void) testOnDisconnectCancelWorks { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; - FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; + FIRDatabaseConfig *readerCfg = [FIRDatabaseConfig configForName:@"reader"]; FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key]; @@ -543,7 +542,7 @@ - (void) testOnDisconnectCancelWorks { } - (void) testOnDisconnectWithServerValuesWithLocalEvents { - FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"]; + FIRDatabaseConfig *writerCfg = [FIRDatabaseConfig configForName:@"writer"]; FIRDatabaseReference * node = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId]; __block FIRDataSnapshot *snap = nil; diff --git a/Example/Database/Tests/Integration/FTransactionTest.m b/Example/Database/Tests/Integration/FTransactionTest.m index d3bb9027ab3..abaea94f246 100644 --- a/Example/Database/Tests/Integration/FTransactionTest.m +++ b/Example/Database/Tests/Integration/FTransactionTest.m @@ -819,7 +819,7 @@ - (void) testMergedTransactionsHaveCorrectSnapshotInOnComplete { // Skipping two tests on nested calls. Since iOS uses a work queue, nested calls don't actually happen synchronously, so they aren't problematic - (void) testPendingTransactionsAreCancelledOnDisconnect { - FIRDatabaseConfig *cfg = [FTestHelpers configForName:@"pending-transactions"]; + FIRDatabaseConfig *cfg = [FIRDatabaseConfig configForName:@"pending-transactions"]; FIRDatabaseReference * ref = [[[FIRDatabaseReference alloc] initWithConfig:cfg] childByAutoId]; __block BOOL done = NO; @@ -1359,7 +1359,7 @@ - (void)testUnsentTransactionsAreNotCancelledOnDisconnect { // In real-world usage the much more common case is that we get redirected to a different // server, but that's harder to manufacture from a test. NSString *configName = @"testUnsentTransactionsAreNotCancelledOnDisconnect"; - FIRDatabaseConfig *config = [FTestHelpers configForName:configName]; + FIRDatabaseConfig *config = [FIRDatabaseConfig configForName:configName]; config.authTokenProvider = [[FIROneBadTokenProvider alloc] init]; // Queue a transaction offline. diff --git a/Example/Database/Tests/Unit/FIRDataSnapshotTests.m b/Example/Database/Tests/Unit/FIRDataSnapshotTests.m index 560568882b2..df950e25d50 100644 --- a/Example/Database/Tests/Unit/FIRDataSnapshotTests.m +++ b/Example/Database/Tests/Unit/FIRDataSnapshotTests.m @@ -46,7 +46,7 @@ - (void)tearDown } - (FIRDataSnapshot *)snapshotFor:(id)jsonDict { - FIRDatabaseConfig *config = [FTestHelpers defaultConfig]; + FIRDatabaseConfig *config = [FIRDatabaseConfig defaultConfig]; FRepoInfo* repoInfo = [[FRepoInfo alloc] initWithHost:@"example.com" isSecure:NO withNamespace:@"default"]; FIRDatabaseReference * dummyRef = [[FIRDatabaseReference alloc] initWithRepo:[FRepoManager getRepo:repoInfo config:config] path:[FPath empty]]; FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:[FSnapshotUtilities nodeFrom:jsonDict]]; diff --git a/Example/Database/Tests/Unit/FUtilitiesTest.m b/Example/Database/Tests/Unit/FUtilitiesTest.m index f0853105af4..1bdc710cb51 100644 --- a/Example/Database/Tests/Unit/FUtilitiesTest.m +++ b/Example/Database/Tests/Unit/FUtilitiesTest.m @@ -22,7 +22,6 @@ #import "FIRDatabaseConfig_Private.h" #import "FWebSocketConnection.h" #import "FConstants.h" -#import "FTestHelpers.h" @interface FWebSocketConnection (Tests) - (NSString*)userAgent; @@ -51,12 +50,12 @@ - (void)testUrlParsedWithoutSchema { } - (void)testDefaultCacheSizeIs10MB { - XCTAssertEqual([FTestHelpers defaultConfig].persistenceCacheSizeBytes, (NSUInteger)10*1024*1024); - XCTAssertEqual([FTestHelpers configForName:@"test-config"].persistenceCacheSizeBytes, (NSUInteger)10*1024*1024); + XCTAssertEqual([FIRDatabaseReference defaultConfig].persistenceCacheSizeBytes, (NSUInteger)10*1024*1024); + XCTAssertEqual([FIRDatabaseConfig configForName:@"test-config"].persistenceCacheSizeBytes, (NSUInteger)10*1024*1024); } - (void)testSettingCacheSizeToHighOrToLowThrows { - FIRDatabaseConfig *config = [FTestHelpers configForName:@"config-tests-config"]; + FIRDatabaseConfig *config = [FIRDatabaseConfig configForName:@"config-tests-config"]; config.persistenceCacheSizeBytes = 5*1024*1024; // Works fine XCTAssertThrows(config.persistenceCacheSizeBytes = (1024*1024-1)); XCTAssertThrows(config.persistenceCacheSizeBytes = 100*1024*1024+1); diff --git a/Example/Firebase.xcodeproj/project.pbxproj b/Example/Firebase.xcodeproj/project.pbxproj index 2c74392c7b4..7390ffe1d4a 100644 --- a/Example/Firebase.xcodeproj/project.pbxproj +++ b/Example/Firebase.xcodeproj/project.pbxproj @@ -129,12 +129,6 @@ AFAF36F71EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; AFAF36F81EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; AFAF36F91EC28C25004BDEE5 /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; - C859EB092193955E008FBD29 /* FIRAuthInteropFake.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E24211A442D00376BFF /* FIRAuthInteropFake.m */; }; - C859EB0A21939565008FBD29 /* FIRAuthInteropFake.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E24211A442D00376BFF /* FIRAuthInteropFake.m */; }; - C859EB0B2193956B008FBD29 /* FIRAuthInteropFake.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E24211A442D00376BFF /* FIRAuthInteropFake.m */; }; - C859EB0C2193956E008FBD29 /* FIRAuthInteropFake.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E24211A442D00376BFF /* FIRAuthInteropFake.m */; }; - C86FBB1121944B2100B3832E /* FIRAuthInteropFake.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E24211A442D00376BFF /* FIRAuthInteropFake.m */; }; - C86FBB1221944C0D00B3832E /* FIRAuthInteropFake.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD53E24211A442D00376BFF /* FIRAuthInteropFake.m */; }; D01853721EDAD084003A645C /* Shared.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFAF36F41EC28C25004BDEE5 /* Shared.xcassets */; }; D01853831EDAD113003A645C /* FIRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D018537E1EDAD0E6003A645C /* FIRAppDelegate.m */; }; D01853841EDAD113003A645C /* FIRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D01853801EDAD0E6003A645C /* FIRViewController.m */; }; @@ -3823,7 +3817,6 @@ 0637BA721EC0F9E000CAEFD4 /* FTupleEventTypeString.m in Sources */, 0637BA6C1EC0F9CB00CAEFD4 /* FTestAuthTokenGenerator.m in Sources */, 0637BA6B1EC0F9C700CAEFD4 /* FMockStorageEngine.m in Sources */, - C86FBB1121944B2100B3832E /* FIRAuthInteropFake.m in Sources */, 0624F3EB1EC0ED0800E5940D /* FConnectionTest.m in Sources */, 0624F3F21EC0ED3F00E5940D /* FKeepSyncedTest.m in Sources */, 0624F3F71EC0ED5600E5940D /* FTransactionTest.m in Sources */, @@ -4010,7 +4003,6 @@ D0FE8A441ED9C86F003F6722 /* FRepoInfoTest.m in Sources */, D0FE8A451ED9C86F003F6722 /* FCompoundHashTest.m in Sources */, D0FE8A461ED9C86F003F6722 /* FTrackedQueryManagerTest.m in Sources */, - C859EB0B2193956B008FBD29 /* FIRAuthInteropFake.m in Sources */, D0FE8A471ED9C86F003F6722 /* FUtilitiesTest.m in Sources */, D0FE8A481ED9C86F003F6722 /* FSparseSnapshotTests.m in Sources */, D0FE8A491ED9C86F003F6722 /* FTestBase.m in Sources */, @@ -4038,7 +4030,6 @@ D0FE8A6B1ED9C87B003F6722 /* FTupleEventTypeString.m in Sources */, D0FE8A6C1ED9C87B003F6722 /* FTestAuthTokenGenerator.m in Sources */, D0FE8A6D1ED9C87B003F6722 /* FMockStorageEngine.m in Sources */, - C86FBB1221944C0D00B3832E /* FIRAuthInteropFake.m in Sources */, D0FE8A6E1ED9C87B003F6722 /* FConnectionTest.m in Sources */, D0FE8A6F1ED9C87B003F6722 /* FKeepSyncedTest.m in Sources */, D0FE8A701ED9C87B003F6722 /* FTransactionTest.m in Sources */, @@ -4129,7 +4120,6 @@ DE90373C1FBA5F8F00E239D3 /* FUtilitiesTest.m in Sources */, DE90372C1FBA5F8F00E239D3 /* FCompoundWriteTest.m in Sources */, DE9037431FBA675D00E239D3 /* FMockStorageEngine.m in Sources */, - C859EB0C2193956E008FBD29 /* FIRAuthInteropFake.m in Sources */, DE9037381FBA5F8F00E239D3 /* FSparseSnapshotTests.m in Sources */, DE9037341FBA5F8F00E239D3 /* FPruningTest.m in Sources */, DE9037471FBA675D00E239D3 /* FTestClock.m in Sources */, @@ -4280,7 +4270,6 @@ files = ( DE7B8DCB1E8EF23A009EB6DF /* FIRViewController.m in Sources */, DE7B8DCC1E8EF23A009EB6DF /* main.m in Sources */, - C859EB0A21939565008FBD29 /* FIRAuthInteropFake.m in Sources */, DE7B8DCA1E8EF23A009EB6DF /* FIRAppDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4306,7 +4295,6 @@ 063CB4D41EBA7B4600038A59 /* FRepoInfoTest.m in Sources */, 063CB4CA1EBA7B4600038A59 /* FCompoundHashTest.m in Sources */, 063CB4D81EBA7B4600038A59 /* FTrackedQueryManagerTest.m in Sources */, - C859EB092193955E008FBD29 /* FIRAuthInteropFake.m in Sources */, 063CB4D91EBA7B4600038A59 /* FUtilitiesTest.m in Sources */, 063CB4D51EBA7B4600038A59 /* FSparseSnapshotTests.m in Sources */, 063CB4D71EBA7B4600038A59 /* FTestBase.m in Sources */, diff --git a/Firebase/Database/Api/FIRDatabase.m b/Firebase/Database/Api/FIRDatabase.m index 1a2ba88800d..b01d6691c45 100644 --- a/Firebase/Database/Api/FIRDatabase.m +++ b/Firebase/Database/Api/FIRDatabase.m @@ -16,31 +16,80 @@ #import -#import #import -#import -#import -#import #import -#import #import "FIRDatabase.h" -#import "FIRDatabaseComponent.h" -#import "FIRDatabaseConfig_Private.h" -#import "FIRDatabaseQuery_Private.h" -#import "FIRDatabaseReference_Private.h" #import "FIRDatabase_Private.h" -#import "FRepoInfo.h" +#import "FIRDatabaseQuery_Private.h" +#import "FRepoManager.h" #import "FValidation.h" +#import "FIRDatabaseConfig_Private.h" +#import "FRepoInfo.h" +#import "FIRDatabaseConfig.h" +#import "FIRDatabaseReference_Private.h" +#import + +@interface FIRDatabase () +@property (nonatomic, strong) FRepoInfo *repoInfo; +@property (nonatomic, strong) FIRDatabaseConfig *config; +@property (nonatomic, strong) FRepo *repo; +@end @implementation FIRDatabase +/** A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase instance. */ +typedef NSMutableDictionary *> FIRDatabaseDictionary; + // The STR and STR_EXPAND macro allow a numeric version passed to he compiler driver // with a -D to be treated as a string instead of an invalid floating point value. #define STR(x) STR_EXPAND(x) #define STR_EXPAND(x) #x static const char *FIREBASE_SEMVER = (const char *)STR(FIRDatabase_VERSION); ++ (void)load { + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserverForName:kFIRAppDeleteNotification + object:nil + queue:nil + usingBlock:^(NSNotification * _Nonnull note) { + NSString *appName = note.userInfo[kFIRAppNameKey]; + if (appName == nil) { return; } + + FIRDatabaseDictionary* instances = [self instances]; + @synchronized (instances) { + NSMutableDictionary *databaseInstances = instances[appName]; + if (databaseInstances) { + // Clean up the deleted instance in an effort to remove any resources still in use. + // Note: Any leftover instances of this exact database will be invalid. + for (FIRDatabase * database in [databaseInstances allValues]) { + [FRepoManager disposeRepos:database.config]; + } + [instances removeObjectForKey:appName]; + } + } + }]; +} + +/** + * A static NSMutableDictionary of FirebaseApp name and FRepoInfo to + * FirebaseDatabase instance. To ensure thread-safety, it should only be + * accessed in databaseForApp:URL:, which is synchronized. + * + * TODO: This serves a duplicate purpose as RepoManager. We should clean up. + * TODO: We should maybe be conscious of leaks and make this a weak map or + * similar but we have a lot of work to do to allow FirebaseDatabase/Repo etc. + * to be GC'd. + */ ++ (FIRDatabaseDictionary *)instances { + static dispatch_once_t pred = 0; + static FIRDatabaseDictionary *instances; + dispatch_once(&pred, ^{ + instances = [NSMutableDictionary dictionary]; + }); + return instances; +} + + (FIRDatabase *)database { if (![FIRApp isDefaultAppConfigured]) { [NSException raise:@"FIRAppNotConfigured" @@ -48,7 +97,8 @@ + (FIRDatabase *)database { @"configure]` (`FirebaseApp.configure()` in Swift) before using " @"Firebase Database."]; } - return [FIRDatabase databaseForApp:[FIRApp defaultApp]]; + FIRApp *app = [FIRApp defaultApp]; + return [FIRDatabase databaseForApp:app]; } + (FIRDatabase *)databaseWithURL:(NSString *)url { @@ -56,8 +106,8 @@ + (FIRDatabase *)databaseWithURL:(NSString *)url { if (app == nil) { [NSException raise:@"FIRAppNotConfigured" format:@"Failed to get default Firebase Database instance. " - @"Must call `[FIRApp configure]` (`FirebaseApp.configure()` in " - @"Swift) before using Firebase Database."]; + @"Must call `[FIRApp configure]` (`FirebaseApp.configure()` in Swift) " + @"before using Firebase Database."]; } return [FIRDatabase databaseForApp:app URL:url]; } @@ -66,21 +116,64 @@ + (FIRDatabase *)databaseForApp:(FIRApp *)app { if (app == nil) { [NSException raise:@"InvalidFIRApp" format:@"nil FIRApp instance passed to databaseForApp."]; } + return [FIRDatabase databaseForApp:app URL:app.options.databaseURL]; } + (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { - if (app == nil) { - [NSException raise:@"InvalidFIRApp" - format:@"nil FIRApp instance passed to databaseForApp."]; - } - if (url == nil) { - [NSException raise:@"MissingDatabaseURL" - format:@"Failed to get FirebaseDatabase instance: " - @"Specify DatabaseURL within FIRApp or from your databaseForApp:URL: call."]; + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + + if (url == nil) { + [NSException raise:@"MissingDatabaseURL" + format:@"Failed to get FirebaseDatabase instance: " + "Specify DatabaseURL within FIRApp or from your databaseForApp:URL: call."]; + } + + NSURL *databaseUrl = [NSURL URLWithString:url]; + + if (databaseUrl == nil) { + [NSException raise:@"InvalidDatabaseURL" format:@"The Database URL '%@' cannot be parsed. " + "Specify a valid DatabaseURL within FIRApp or from your databaseForApp:URL: call.", databaseUrl]; + } else if (![databaseUrl.path isEqualToString:@""] && ![databaseUrl.path isEqualToString:@"/"]) { + [NSException raise:@"InvalidDatabaseURL" format:@"Configured Database URL '%@' is invalid. It should point " + "to the root of a Firebase Database but it includes a path: %@",databaseUrl, databaseUrl.path]; } - id provider = FIR_COMPONENT(FIRDatabaseProvider, app.container); - return [provider databaseForApp:app URL:url]; + + FIRDatabaseDictionary *instances = [self instances]; + @synchronized (instances) { + NSMutableDictionary *urlInstanceMap = + instances[app.name]; + if (!urlInstanceMap) { + urlInstanceMap = [NSMutableDictionary dictionary]; + instances[app.name] = urlInstanceMap; + } + + FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl.absoluteString]; + FIRDatabase *database = urlInstanceMap[parsedUrl.repoInfo]; + if (!database) { + id authTokenProvider = [FAuthTokenProvider authTokenProviderForApp:app]; + + // If this is the default app, don't set the session persistence key so that we use our + // default ("default") instead of the FIRApp default ("[DEFAULT]") so that we + // preserve the default location used by the legacy Firebase SDK. + NSString *sessionIdentifier = @"default"; + if (![FIRApp isDefaultAppConfigured] || app != [FIRApp defaultApp]) { + sessionIdentifier = app.name; + } + + FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc] initWithSessionIdentifier:sessionIdentifier + authTokenProvider:authTokenProvider]; + database = [[FIRDatabase alloc] initWithApp:app + repoInfo:parsedUrl.repoInfo + config:config]; + urlInstanceMap[parsedUrl.repoInfo] = database; + } + + return database; + } } + (NSString *) buildVersion { @@ -94,6 +187,7 @@ + (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo config:(FIRDatabas return db; } + + (NSString *) sdkVersion { return [NSString stringWithUTF8String:FIREBASE_SEMVER]; } diff --git a/Firebase/Database/Api/FIRDatabaseComponent.h b/Firebase/Database/Api/FIRDatabaseComponent.h deleted file mode 100644 index 37840a1f87c..00000000000 --- a/Firebase/Database/Api/FIRDatabaseComponent.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import - -@class FIRApp; -@class FIRDatabase; - -NS_ASSUME_NONNULL_BEGIN - -/// This protocol is used in the interop registration process to register an instance provider for -/// individual FIRApps. -@protocol FIRDatabaseProvider - -/// Gets a FirebaseDatabase instance for the specified URL, using the specified FirebaseApp. -- (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url; - -@end - -/// A concrete implementation for FIRDatabaseProvider to create Database instances. -@interface FIRDatabaseComponent : NSObject - -/// The FIRApp that instances will be set up with. -@property(nonatomic, weak, readonly) FIRApp *app; - -/// Unavailable, use `databaseForApp:URL:` instead. -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firebase/Database/Api/FIRDatabaseComponent.m b/Firebase/Database/Api/FIRDatabaseComponent.m deleted file mode 100644 index 653a21e2864..00000000000 --- a/Firebase/Database/Api/FIRDatabaseComponent.m +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2018 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "FIRDatabaseComponent.h" - -#import "FIRDatabase_Private.h" -#import "FIRDatabaseConfig_Private.h" -#import "FRepoManager.h" - -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -/** A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase instance. */ -typedef NSMutableDictionary FIRDatabaseDictionary; - -@interface FIRDatabaseComponent () -@property (nonatomic) FIRDatabaseDictionary *instances; -/// Internal intializer. -- (instancetype)initWithApp:(FIRApp *)app; -@end - -@implementation FIRDatabaseComponent - -#pragma mark - Initialization - -- (instancetype)initWithApp:(FIRApp *)app { - self = [super init]; - if (self) { - _app = app; - _instances = [NSMutableDictionary dictionary]; - } - return self; -} - -#pragma mark - Lifecycle - -+ (void)load { - [FIRComponentContainer registerAsComponentRegistrant:self]; -} - -#pragma mark - FIRComponentRegistrant - -+ (NSArray *)componentsToRegister { - FIRDependency *authDep = - [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop) isRequired:NO]; - FIRComponentCreationBlock creationBlock = - ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { - *isCacheable = YES; - return [[FIRDatabaseComponent alloc] initWithApp:container.app]; - }; - FIRComponent *databaseProvider = - [FIRComponent componentWithProtocol:@protocol(FIRDatabaseProvider) - instantiationTiming:FIRInstantiationTimingLazy - dependencies:@[ authDep ] - creationBlock:creationBlock]; - return @[ databaseProvider ]; -} - -#pragma mark - Instance management. - -- (void)appWillBeDeleted:(FIRApp *)app { - NSString *appName = app.name; - if (appName == nil) { - return; - } - FIRDatabaseDictionary* instances = [self instances]; - @synchronized (instances) { - // Clean up the deleted instance in an effort to remove any resources still in use. - // Note: Any leftover instances of this exact database will be invalid. - for (FIRDatabase * database in [instances allValues]) { - [FRepoManager disposeRepos:database.config]; - } - [instances removeAllObjects]; - } -} - -#pragma mark - FIRDatabaseProvider Conformance - - -- (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { - if (app == nil) { - [NSException raise:@"InvalidFIRApp" - format:@"nil FIRApp instance passed to databaseForApp."]; - } - - if (url == nil) { - [NSException raise:@"MissingDatabaseURL" - format:@"Failed to get FirebaseDatabase instance: " - "Specify DatabaseURL within FIRApp or from your databaseForApp:URL: call."]; - } - - NSURL *databaseUrl = [NSURL URLWithString:url]; - - if (databaseUrl == nil) { - [NSException raise:@"InvalidDatabaseURL" format:@"The Database URL '%@' cannot be parsed. " - "Specify a valid DatabaseURL within FIRApp or from your databaseForApp:URL: call.", databaseUrl]; - } else if (![databaseUrl.path isEqualToString:@""] && ![databaseUrl.path isEqualToString:@"/"]) { - [NSException raise:@"InvalidDatabaseURL" format:@"Configured Database URL '%@' is invalid. It should point " - "to the root of a Firebase Database but it includes a path: %@",databaseUrl, databaseUrl.path]; - } - - FIRDatabaseDictionary *instances = [self instances]; - @synchronized (instances) { - FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl.absoluteString]; - FIRDatabase *database = instances[url]; - if (!database) { - id authTokenProvider = - [FAuthTokenProvider authTokenProviderWithAuth: - FIR_COMPONENT(FIRAuthInterop, app.container)]; - - // If this is the default app, don't set the session persistence key so that we use our - // default ("default") instead of the FIRApp default ("[DEFAULT]") so that we - // preserve the default location used by the legacy Firebase SDK. - NSString *sessionIdentifier = @"default"; - if (![FIRApp isDefaultAppConfigured] || app != [FIRApp defaultApp]) { - sessionIdentifier = app.name; - } - - FIRDatabaseConfig *config = - [[FIRDatabaseConfig alloc] initWithSessionIdentifier:sessionIdentifier - authTokenProvider:authTokenProvider]; - database = [[FIRDatabase alloc] initWithApp:app - repoInfo:parsedUrl.repoInfo - config:config]; - instances[url] = database; - } - - return database; - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firebase/Database/Api/FIRDatabaseConfig.m b/Firebase/Database/Api/FIRDatabaseConfig.m index a49d4a0ac97..3341c7e02a9 100644 --- a/Firebase/Database/Api/FIRDatabaseConfig.m +++ b/Firebase/Database/Api/FIRDatabaseConfig.m @@ -14,11 +14,11 @@ * limitations under the License. */ +#import #import "FIRDatabaseConfig.h" - -#import "FAuthTokenProvider.h" #import "FIRDatabaseConfig_Private.h" #import "FIRNoopAuthTokenProvider.h" +#import "FAuthTokenProvider.h" @interface FIRDatabaseConfig (Private) @@ -81,4 +81,37 @@ - (void)freeze { self->_isFrozen = YES; } +// TODO: Only used for tests. Migrate to FIRDatabase and remove. ++ (FIRDatabaseConfig *)defaultConfig { + static dispatch_once_t onceToken; + static FIRDatabaseConfig *defaultConfig; + dispatch_once(&onceToken, ^{ + defaultConfig = [FIRDatabaseConfig configForName:@"default"]; + }); + return defaultConfig; +} + +// TODO: This is only used for tests. We should fix them to go through FIRDatabase and remove +// this method and the sessionsConfigs dictionary (FIRDatabase automatically creates one config per app). ++ (FIRDatabaseConfig *)configForName:(NSString *)name { + NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"^[a-zA-Z0-9-_]+$" options:0 error:nil]; + if ([expression numberOfMatchesInString:name options:0 range:NSMakeRange(0, name.length)] == 0) { + [NSException raise:NSInvalidArgumentException format:@"Name can only contain [a-zA-Z0-9-_]"]; + } + + static dispatch_once_t onceToken; + static NSMutableDictionary *sessionConfigs; + dispatch_once(&onceToken, ^{ + sessionConfigs = [NSMutableDictionary dictionary]; + }); + @synchronized(sessionConfigs) { + if (!sessionConfigs[name]) { + id authTokenProvider = [FAuthTokenProvider authTokenProviderForApp:[FIRApp defaultApp]]; + sessionConfigs[name] = [[FIRDatabaseConfig alloc] initWithSessionIdentifier:name + authTokenProvider:authTokenProvider]; + } + return sessionConfigs[name]; + } +} + @end diff --git a/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h b/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h index 6063cb83cb8..cb28febf27a 100644 --- a/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h +++ b/Firebase/Database/Api/Private/FIRDatabaseReference_Private.h @@ -24,4 +24,6 @@ - (id)initWithConfig:(FIRDatabaseConfig *)config; - (id)initWithRepo:(FRepo *)repo path:(FPath *)path; +// TODO: Update tests to not use this. ++ (FIRDatabaseConfig *)defaultConfig; @end diff --git a/Firebase/Database/Api/Private/FIRDatabase_Private.h b/Firebase/Database/Api/Private/FIRDatabase_Private.h index 5e294519559..5b7f8cc4d3e 100644 --- a/Firebase/Database/Api/Private/FIRDatabase_Private.h +++ b/Firebase/Database/Api/Private/FIRDatabase_Private.h @@ -22,12 +22,6 @@ @interface FIRDatabase () -@property (nonatomic, strong) FRepoInfo *repoInfo; -@property (nonatomic, strong) FIRDatabaseConfig *config; -@property (nonatomic, strong) FRepo *repo; - -- (id)initWithApp:(FIRApp *)app repoInfo:(FRepoInfo *)info config:(FIRDatabaseConfig *)config; - + (NSString *) buildVersion; + (FIRDatabase *) createDatabaseForTests:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config; diff --git a/Firebase/Database/FIRDatabaseConfig_Private.h b/Firebase/Database/FIRDatabaseConfig_Private.h index ac37f2e2bbe..b0a9dc43dec 100644 --- a/Firebase/Database/FIRDatabaseConfig_Private.h +++ b/Firebase/Database/FIRDatabaseConfig_Private.h @@ -28,4 +28,8 @@ - (void)freeze; ++ (FIRDatabaseConfig *)configForName:(NSString *)name; + ++ (FIRDatabaseConfig *)defaultConfig; + @end diff --git a/Firebase/Database/FIRDatabaseReference.m b/Firebase/Database/FIRDatabaseReference.m index 3ea5992f08f..bdbbdfd5b38 100644 --- a/Firebase/Database/FIRDatabaseReference.m +++ b/Firebase/Database/FIRDatabaseReference.m @@ -31,6 +31,10 @@ @implementation FIRDatabaseReference ++ (FIRDatabaseConfig *)defaultConfig { + return [FIRDatabaseConfig defaultConfig]; +} + #pragma mark - #pragma mark Constructors diff --git a/Firebase/Database/Login/FAuthTokenProvider.h b/Firebase/Database/Login/FAuthTokenProvider.h index a4f8b156f28..363b82f082c 100644 --- a/Firebase/Database/Login/FAuthTokenProvider.h +++ b/Firebase/Database/Login/FAuthTokenProvider.h @@ -19,20 +19,19 @@ #import "FTypedefs.h" #import "FTypedefs_Private.h" -@protocol FIRAuthInterop; +@class FIRApp; @protocol FAuthTokenProvider -- (void)fetchTokenForcingRefresh:(BOOL)forceRefresh - withCallback:(fbt_void_nsstring_nserror)callback; +- (void) fetchTokenForcingRefresh:(BOOL)forceRefresh withCallback:(fbt_void_nsstring_nserror)callback; -- (void)listenForTokenChanges:(fbt_void_nsstring)listener; +- (void) listenForTokenChanges:(fbt_void_nsstring)listener; @end @interface FAuthTokenProvider : NSObject -+ (id)authTokenProviderWithAuth:(id)auth; ++ (id) authTokenProviderForApp:(FIRApp *)app; - (instancetype)init NS_UNAVAILABLE; diff --git a/Firebase/Database/Login/FAuthTokenProvider.m b/Firebase/Database/Login/FAuthTokenProvider.m index 50103602815..11da56dc156 100644 --- a/Firebase/Database/Login/FAuthTokenProvider.m +++ b/Firebase/Database/Login/FAuthTokenProvider.m @@ -15,30 +15,27 @@ */ #import "FAuthTokenProvider.h" - -#import +#import "FUtilities.h" #import -#import #import - -#import "FUtilities.h" #import "FIRDatabaseQuery_Private.h" #import "FIRNoopAuthTokenProvider.h" @interface FAuthStateListenerWrapper : NSObject @property (nonatomic, copy) fbt_void_nsstring listener; -@property (nonatomic, weak) id auth; + +@property (nonatomic, weak) FIRApp *app; @end @implementation FAuthStateListenerWrapper -- (instancetype)initWithListener:(fbt_void_nsstring)listener auth:(id)auth { +- (instancetype) initWithListener:(fbt_void_nsstring)listener app:(FIRApp *)app { self = [super init]; if (self != nil) { self->_listener = listener; - self->_auth = auth; + self->_app = app; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(authStateDidChangeNotification:) name:FIRAuthStateDidChangeInternalNotification @@ -47,9 +44,10 @@ - (instancetype)initWithListener:(fbt_void_nsstring)listener auth:(id -@property (nonatomic, strong) id auth; +@property (nonatomic, strong) FIRApp *app; /** Strong references to the auth listeners as they are only weak in FIRFirebaseApp */ @property (nonatomic, strong) NSMutableArray *authListeners; -- (instancetype) initWithAuth:(id)auth; +- (instancetype) initWithFirebaseApp:(FIRApp *)app; @end @implementation FIRFirebaseAuthTokenProvider -- (instancetype)initWithAuth:(id)auth { +- (instancetype) initWithFirebaseApp:(FIRApp *)app { self = [super init]; if (self != nil) { - self->_auth = auth; + self->_app = app; self->_authListeners = [NSMutableArray array]; } return self; } -- (void)fetchTokenForcingRefresh:(BOOL)forceRefresh - withCallback:(fbt_void_nsstring_nserror)callback { - if (self.auth == nil) { - // Signal that Auth is not available by returning nil. - callback(nil, nil); - } else { - [self.auth getTokenForcingRefresh:forceRefresh - withCallback:^(NSString * _Nullable token, NSError * _Nullable error) { +- (void) fetchTokenForcingRefresh:(BOOL)forceRefresh withCallback:(fbt_void_nsstring_nserror)callback { + // TODO: Don't fetch token if there is no current user + [self.app getTokenForcingRefresh:forceRefresh withCallback:^(NSString * _Nullable token, NSError * _Nullable error) { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ callback(token, error); }); }]; - } } -- (void)listenForTokenChanges:(_Nonnull fbt_void_nsstring)listener { - FAuthStateListenerWrapper *wrapper = - [[FAuthStateListenerWrapper alloc] initWithListener:listener auth:self.auth]; +- (void) listenForTokenChanges:(_Nonnull fbt_void_nsstring)listener { + FAuthStateListenerWrapper *wrapper = [[FAuthStateListenerWrapper alloc] initWithListener:listener app:self.app]; [self.authListeners addObject:wrapper]; } @@ -110,8 +101,8 @@ - (void)listenForTokenChanges:(_Nonnull fbt_void_nsstring)listener { @implementation FAuthTokenProvider -+ (id)authTokenProviderWithAuth:(id)authInterop { - return [[FIRFirebaseAuthTokenProvider alloc] initWithAuth:authInterop]; ++ (id) authTokenProviderForApp:(id)app { + return [[FIRFirebaseAuthTokenProvider alloc] initWithFirebaseApp:app]; } @end diff --git a/FirebaseDatabase.podspec b/FirebaseDatabase.podspec index 13fca0dd52e..f3677c201c4 100644 --- a/FirebaseDatabase.podspec +++ b/FirebaseDatabase.podspec @@ -32,8 +32,7 @@ Simplify your iOS development, grow your user base, and monetize more effectivel s.libraries = ['c++', 'icucore'] s.frameworks = 'CFNetwork', 'Security', 'SystemConfiguration' s.dependency 'leveldb-library', '~> 1.18' - s.dependency 'FirebaseAuthInterop', '~> 1.0' - s.dependency 'FirebaseCore', '~> 5.1' + s.dependency 'FirebaseCore', '~> 5.0' s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' =>