Skip to content

Commit 68628ef

Browse files
authored
Implement MultiDB Support and Tests (#10465)
1 parent 7196035 commit 68628ef

File tree

7 files changed

+135
-29
lines changed

7 files changed

+135
-29
lines changed

Firestore/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
- [fixed] Fix FAILED_PRECONDITION when writing to a deleted document in a
33
transaction (#10431).
44
- [fixed] Fixed data race in credentials provider (#10393).
5+
- [feature] Add MultiDb support.
56
- [fixed] Fix Firestore failing to raise initial snapshot from empty local cache
67
result (#10437).
78

Firestore/Example/Tests/Integration/API/FIRDatabaseTests.mm

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@
2525

2626
#include "Firestore/core/src/api/query_snapshot.h"
2727
#include "Firestore/core/src/core/firestore_client.h"
28+
#include "Firestore/core/src/model/database_id.h"
29+
#include "Firestore/core/src/util/string_apple.h"
2830
#include "Firestore/core/test/unit/testutil/app_testing.h"
2931

32+
using firebase::firestore::model::DatabaseId;
3033
using firebase::firestore::testutil::AppForUnitTesting;
34+
using firebase::firestore::util::MakeNSString;
3135
using firebase::firestore::util::MakeString;
3236
using firebase::firestore::util::TimerId;
3337

@@ -36,6 +40,11 @@ @interface FIRDatabaseTests : FSTIntegrationTestCase
3640

3741
@implementation FIRDatabaseTests
3842

43+
- (void)tearDown {
44+
[FIRApp resetApps];
45+
[super tearDown];
46+
}
47+
3948
- (void)testCanUpdateAnExistingDocument {
4049
FIRDocumentReference *doc = [self.db documentWithPath:@"rooms/eros"];
4150
NSDictionary<NSString *, id> *initialData =
@@ -1744,4 +1753,37 @@ - (void)testWaitForPendingWritesCompletesWhenOfflineIfNoPending {
17441753
[self awaitExpectations];
17451754
}
17461755

1756+
- (void)testDefaultNamedDbIsSame {
1757+
[FIRApp configure];
1758+
FIRApp *app = [FIRApp defaultApp];
1759+
FIRFirestore *db1 = [FIRFirestore firestore];
1760+
FIRFirestore *db2 = [FIRFirestore firestoreForApp:app];
1761+
FIRFirestore *db3 = [FIRFirestore firestoreForApp:app database:@"(default)"];
1762+
FIRFirestore *db4 = [FIRFirestore firestoreForDatabase:@"(default)"];
1763+
1764+
XCTAssertIdentical(db1, db2);
1765+
XCTAssertIdentical(db1, db3);
1766+
XCTAssertIdentical(db1, db4);
1767+
}
1768+
1769+
- (void)testSameNamedDbIsSame {
1770+
[FIRApp configure];
1771+
FIRApp *app = [FIRApp defaultApp];
1772+
FIRFirestore *db1 = [FIRFirestore firestoreForApp:app database:@"myDb"];
1773+
FIRFirestore *db2 = [FIRFirestore firestoreForDatabase:@"myDb"];
1774+
1775+
XCTAssertIdentical(db1, db2);
1776+
}
1777+
1778+
- (void)testNamedDbHaveDifferentInstance {
1779+
[FIRApp configure];
1780+
FIRFirestore *db1 = [FIRFirestore firestore];
1781+
FIRFirestore *db2 = [FIRFirestore firestoreForDatabase:@"db1"];
1782+
FIRFirestore *db3 = [FIRFirestore firestoreForDatabase:@"db2"];
1783+
1784+
XCTAssertNotIdentical(db1, db2);
1785+
XCTAssertNotIdentical(db1, db3);
1786+
XCTAssertNotIdentical(db2, db3);
1787+
}
1788+
17471789
@end

Firestore/Example/Tests/Integration/API/FIRValidationTests.mm

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
#import <XCTest/XCTest.h>
2020
#include <limits>
2121

22+
#import "FirebaseCore/Extension/FIRAppInternal.h"
2223
#import "FirebaseCore/Extension/FIROptionsInternal.h"
2324
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
2425
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
2526
#import "Firestore/Source/API/FIRFieldValue+Internal.h"
2627
#import "Firestore/Source/API/FIRFilter+Internal.h"
28+
#import "Firestore/Source/API/FIRFirestore+Internal.h"
2729
#import "Firestore/Source/API/FIRQuery+Internal.h"
2830
#include "Firestore/core/test/unit/testutil/app_testing.h"
2931

@@ -38,6 +40,11 @@ @interface FIRValidationTests : FSTIntegrationTestCase
3840

3941
@implementation FIRValidationTests
4042

43+
- (void)tearDown {
44+
[FIRApp resetApps];
45+
[super tearDown];
46+
}
47+
4148
#pragma mark - FIRFirestoreSettings Validation
4249

4350
- (void)testNilHostFails {
@@ -74,6 +81,27 @@ - (void)testNilFIRAppFails {
7481
"default FirebaseApp instance.");
7582
}
7683

84+
- (void)testNilFIRAppDatabaseFails1 {
85+
FIRApp *app = AppForUnitTesting();
86+
FSTAssertThrows(
87+
[FIRFirestore firestoreForApp:app database:nil],
88+
@"Database identifier may not be nil. Use '(default)' if you want the default database");
89+
}
90+
91+
- (void)testNilFIRAppDatabaseFails2 {
92+
FSTAssertThrows(
93+
[FIRFirestore firestoreForApp:nil database:@"NotNil"],
94+
@"FirebaseApp instance may not be nil. Use FirebaseApp.app() if you'd like to use the "
95+
"default FirebaseApp instance.");
96+
}
97+
98+
- (void)testNilDatabaseFails {
99+
[FIRApp configure];
100+
FSTAssertThrows(
101+
[FIRFirestore firestoreForDatabase:nil],
102+
@"Database identifier may not be nil. Use '(default)' if you want the default database");
103+
}
104+
77105
- (void)testNilProjectIDFails {
78106
FIROptions *options = OptionsForUnitTesting("ignored");
79107
options.projectID = nil;
@@ -82,8 +110,6 @@ - (void)testNilProjectIDFails {
82110
@"FIROptions.projectID must be set to a valid project ID.");
83111
}
84112

85-
// TODO(b/62410906): Test for firestoreForApp:database: with nil DatabaseID.
86-
87113
- (void)testNilTransactionBlocksFail {
88114
FSTAssertThrows([self.db runTransactionWithBlock:nil
89115
completion:^(id, NSError *) {

Firestore/Example/Tests/Integration/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ if(NOT FIREBASE_IOS_BUILD_TESTS OR NOT APPLE)
1616
return()
1717
endif()
1818

19-
file(GLOB sources *.h *.mm API/*.h API/*.mm)
19+
file(GLOB sources *.h *.mm API/*.h API/*.mm ../../App/GoogleService-Info.plist)
2020

2121
firebase_ios_add_objc_test(
2222
firestore_objc_integration_test
@@ -30,3 +30,8 @@ target_link_libraries(
3030
firestore_core
3131
firestore_objc_testing
3232
)
33+
34+
set_target_properties(
35+
firestore_objc_integration_test PROPERTIES
36+
RESOURCE ../../App/GoogleService-Info.plist
37+
)

Firestore/Source/API/FIRFirestore+Internal.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,30 @@ NS_ASSUME_NONNULL_BEGIN
8383
@property(nonatomic, assign, readonly) const model::DatabaseId &databaseID;
8484
@property(nonatomic, strong, readonly) FSTUserDataReader *dataReader;
8585

86+
/**
87+
* Creates, caches, and returns named `Firestore` object for the specified `FirebaseApp`. Each
88+
* subsequent invocation returns the same `Firestore` object.
89+
*
90+
* @param app The `FirebaseApp` instance to use for authentication and as a source of the Google
91+
* Cloud Project ID for your Firestore Database. If you want the default instance, you should
92+
* explicitly set it to `FirebaseApp.app()`.
93+
* @param database The database name.
94+
*
95+
* @return The named `Firestore` instance.
96+
*/
97+
+ (instancetype)firestoreForApp:(FIRApp *)app
98+
database:(NSString *)database NS_SWIFT_NAME(firestore(app:database:));
99+
100+
/**
101+
* Creates, caches, and returns named `Firestore` object for the default _app_. Each subsequent
102+
* invocation returns the same `Firestore` object.
103+
*
104+
* @param database The database name.
105+
*
106+
* @return The named `Firestore` instance.
107+
*/
108+
+ (instancetype)firestoreForDatabase:(NSString *)database NS_SWIFT_NAME(firestore(database:));
109+
86110
@end
87111

88112
NS_ASSUME_NONNULL_END

Firestore/Source/API/FIRFirestore.mm

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@
7474
using firebase::firestore::util::Empty;
7575
using firebase::firestore::util::Executor;
7676
using firebase::firestore::util::ExecutorLibdispatch;
77+
using firebase::firestore::util::kLogLevelDebug;
78+
using firebase::firestore::util::kLogLevelNotice;
7779
using firebase::firestore::util::LogSetLevel;
7880
using firebase::firestore::util::MakeCallback;
7981
using firebase::firestore::util::MakeNSError;
@@ -83,11 +85,9 @@
8385
using firebase::firestore::util::SetThrowHandler;
8486
using firebase::firestore::util::Status;
8587
using firebase::firestore::util::StatusOr;
88+
using firebase::firestore::util::StreamReadResult;
8689
using firebase::firestore::util::ThrowIllegalState;
8790
using firebase::firestore::util::ThrowInvalidArgument;
88-
using firebase::firestore::util::kLogLevelDebug;
89-
using firebase::firestore::util::kLogLevelNotice;
90-
using firebase::firestore::util::StreamReadResult;
9191

9292
using UserUpdateBlock = id _Nullable (^)(FIRTransaction *, NSError **);
9393
using UserTransactionCompletion = void (^)(id _Nullable, NSError *_Nullable);
@@ -128,23 +128,6 @@ + (instancetype)firestoreForApp:(FIRApp *)app {
128128
return [self firestoreForApp:app database:MakeNSString(DatabaseId::kDefault)];
129129
}
130130

131-
// TODO(b/62410906): make this public
132-
+ (instancetype)firestoreForApp:(FIRApp *)app database:(NSString *)database {
133-
if (!app) {
134-
ThrowInvalidArgument("FirebaseApp instance may not be nil. Use FirebaseApp.app() if you'd like "
135-
"to use the default FirebaseApp instance.");
136-
}
137-
if (!database) {
138-
ThrowInvalidArgument("Database identifier may not be nil. Use '%s' if you want the default "
139-
"database",
140-
DatabaseId::kDefault);
141-
}
142-
143-
id<FSTFirestoreMultiDBProvider> provider =
144-
FIR_COMPONENT(FSTFirestoreMultiDBProvider, app.container);
145-
return [provider firestoreForDatabase:database];
146-
}
147-
148131
- (instancetype)initWithDatabaseID:(model::DatabaseId)databaseID
149132
persistenceKey:(std::string)persistenceKey
150133
authCredentialsProvider:
@@ -529,6 +512,31 @@ @implementation FIRFirestore (Internal)
529512
return _firestore->database_id();
530513
}
531514

515+
+ (instancetype)firestoreForApp:(FIRApp *)app database:(NSString *)database {
516+
if (!app) {
517+
ThrowInvalidArgument("FirebaseApp instance may not be nil. Use FirebaseApp.app() if you'd like "
518+
"to use the default FirebaseApp instance.");
519+
}
520+
if (!database) {
521+
ThrowInvalidArgument("Database identifier may not be nil. Use '%s' if you want the default "
522+
"database",
523+
DatabaseId::kDefault);
524+
}
525+
526+
id<FSTFirestoreMultiDBProvider> provider =
527+
FIR_COMPONENT(FSTFirestoreMultiDBProvider, app.container);
528+
return [provider firestoreForDatabase:database];
529+
}
530+
531+
+ (instancetype)firestoreForDatabase:(NSString *)database {
532+
FIRApp *app = [FIRApp defaultApp];
533+
if (!app) {
534+
ThrowIllegalState("Failed to get FirebaseApp instance. Please call FirebaseApp.configure() "
535+
"before using Firestore");
536+
}
537+
return [self firestoreForApp:app database:database];
538+
}
539+
532540
+ (FIRFirestore *)recoverFromFirestore:(std::shared_ptr<Firestore>)firestore {
533541
return (__bridge FIRFirestore *)firestore->extension();
534542
}

Firestore/Source/Public/FirebaseFirestore/FIRFirestore.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,22 @@ NS_SWIFT_NAME(Firestore)
4343
- (instancetype)init __attribute__((unavailable("Use a static constructor method.")));
4444

4545
/**
46-
* Creates, caches, and returns a `Firestore` using the default `FirebaseApp`. Each subsequent
47-
* invocation returns the same `Firestore` object.
46+
* Creates, caches, and returns the default `Firestore` using the default `FirebaseApp`. Each
47+
* subsequent invocation returns the same `Firestore` object.
4848
*
49-
* @return The `Firestore` instance.
49+
* @return The default `Firestore` instance.
5050
*/
5151
+ (instancetype)firestore NS_SWIFT_NAME(firestore());
5252

5353
/**
54-
* Creates, caches, and returns a `Firestore` object for the specified _app_. Each subsequent
55-
* invocation returns the same `Firestore` object.
54+
* Creates, caches, and returns the default `Firestore` object for the specified _app_. Each
55+
* subsequent invocation returns the same `Firestore` object.
5656
*
5757
* @param app The `FirebaseApp` instance to use for authentication and as a source of the Google
5858
* Cloud Project ID for your Firestore Database. If you want the default instance, you should
5959
* explicitly set it to `FirebaseApp.app()`.
6060
*
61-
* @return The `Firestore` instance.
61+
* @return The default `Firestore` instance.
6262
*/
6363
+ (instancetype)firestoreForApp:(FIRApp *)app NS_SWIFT_NAME(firestore(app:));
6464

0 commit comments

Comments
 (0)