FIRDatabaseTests.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <XCTest/XCTest.h>
  17. #import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
  18. #import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h"
  19. #import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h"
  20. #import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h"
  21. #import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h"
  22. #import "FirebaseDatabase/Tests/Helpers/FIRFakeApp.h"
  23. #import "FirebaseDatabase/Tests/Helpers/FMockStorageEngine.h"
  24. #import "FirebaseDatabase/Tests/Helpers/FTestBase.h"
  25. #import "FirebaseDatabase/Tests/Helpers/FTestHelpers.h"
  26. @interface FIRDatabaseTests : FTestBase
  27. @end
  28. static const NSInteger kFErrorCodeWriteCanceled = 3;
  29. static NSString *kFirebaseTestAltNamespace = @"https://foobar.firebaseio.com";
  30. @implementation FIRDatabaseTests
  31. - (void)testFIRDatabaseForNilApp {
  32. #pragma clang diagnostic push
  33. #pragma clang diagnostic ignored "-Wnonnull"
  34. XCTAssertThrowsSpecificNamed([FIRDatabase databaseForApp:nil], NSException, @"InvalidFIRApp");
  35. #pragma clang diagnostic pop
  36. }
  37. - (void)testDatabaseForApp {
  38. FIRDatabase *database = [self databaseForURL:self.databaseURL];
  39. XCTAssertEqualObjects(self.databaseURL, [database reference].URL);
  40. }
  41. - (void)testDatabaseForAppWithInvalidURLs {
  42. XCTAssertThrows([self databaseForURL:@"not-a-url"]);
  43. XCTAssertThrows([self databaseForURL:@"http://x.example.com/paths/are/bad"]);
  44. }
  45. - (void)testDatabaseForAppWithURL {
  46. id app = [[FIRFakeApp alloc] initWithName:@"testDatabaseForAppWithURL"
  47. URL:kFirebaseTestAltNamespace];
  48. FIRDatabase *database = [FIRDatabase databaseForApp:app URL:@"http://foo.bar.com"];
  49. XCTAssertEqualObjects(@"https://foo.bar.com", [database reference].URL);
  50. }
  51. - (void)testDatabaseForAppWithURLAndPort {
  52. id app = [[FIRFakeApp alloc] initWithName:@"testDatabaseForAppWithURLAndPort"
  53. URL:kFirebaseTestAltNamespace];
  54. FIRDatabase *database = [FIRDatabase databaseForApp:app URL:@"http://foo.bar.com:80"];
  55. XCTAssertEqualObjects(@"http://foo.bar.com:80", [database reference].URL);
  56. }
  57. - (void)testDatabaseForAppWithHttpsURL {
  58. id app = [[FIRFakeApp alloc] initWithName:@"testDatabaseForAppWithHttpsURL"
  59. URL:kFirebaseTestAltNamespace];
  60. FIRDatabase *database = [FIRDatabase databaseForApp:app URL:@"https://foo.bar.com"];
  61. XCTAssertEqualObjects(@"https://foo.bar.com", [database reference].URL);
  62. }
  63. - (void)testDatabaseForAppWithProjectId {
  64. id app = [[FIRFakeApp alloc] initWithName:@"testDatabaseForAppWithURL" URL:nil];
  65. FIRDatabase *database = [FIRDatabase databaseForApp:app];
  66. XCTAssertEqualObjects(@"https://fake-project-id-default-rtdb.firebaseio.com",
  67. [database reference].URL);
  68. }
  69. - (void)testDifferentInstanceForAppWithURL {
  70. id app = [[FIRFakeApp alloc] initWithName:@"testDifferentInstanceForAppWithURL"
  71. URL:kFirebaseTestAltNamespace];
  72. FIRDatabase *database1 = [FIRDatabase databaseForApp:app URL:@"https://foo1.bar.com"];
  73. FIRDatabase *database2 = [FIRDatabase databaseForApp:app URL:@"https://foo1.bar.com/"];
  74. FIRDatabase *database3 = [FIRDatabase databaseForApp:app URL:@"https://foo2.bar.com"];
  75. XCTAssertEqual(database1, database2);
  76. XCTAssertNotEqual(database1, database3);
  77. }
  78. - (void)testDatabaseForAppWithInvalidCustomURLs {
  79. id app = [[FIRFakeApp alloc] initWithName:@"testDatabaseForAppWithInvalidCustomURLs"
  80. URL:kFirebaseTestAltNamespace];
  81. #pragma clang diagnostic push
  82. #pragma clang diagnostic ignored "-Wnonnull"
  83. XCTAssertThrows([FIRDatabase databaseForApp:app URL:nil]);
  84. #pragma clang diagnostic pop
  85. XCTAssertThrows([FIRDatabase databaseForApp:app URL:@"not-a-url"]);
  86. XCTAssertThrows([FIRDatabase databaseForApp:app URL:@"http://x.fblocal.com:9000/paths/are/bad"]);
  87. }
  88. - (void)testDeleteDatabase {
  89. // Set up a custom FIRApp with a custom database based on it.
  90. FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:@"1:123:ios:123abc"
  91. GCMSenderID:@"gcm_sender_id"];
  92. options.databaseURL = self.databaseURL;
  93. NSString *customAppName = @"MyCustomApp";
  94. [FIRApp configureWithName:customAppName options:options];
  95. FIRApp *customApp = [FIRApp appNamed:customAppName];
  96. FIRDatabase *customDatabase = [FIRDatabase databaseForApp:customApp];
  97. XCTAssertNotNil(customDatabase);
  98. // Delete the custom app and wait for it to be done.
  99. XCTestExpectation *customAppDeletedExpectation =
  100. [self expectationWithDescription:@"Deleting the custom app should be successful."];
  101. [customApp deleteApp:^(BOOL success) {
  102. // The app shouldn't exist anymore, ensure that the databaseForApp throws.
  103. XCTAssertThrows([FIRDatabase databaseForApp:[FIRApp appNamed:customAppName]]);
  104. [customAppDeletedExpectation fulfill];
  105. }];
  106. // Wait for the custom app to be deleted.
  107. [self waitForExpectations:@[ customAppDeletedExpectation ] timeout:2];
  108. // Configure the app again, then grab a reference to the database. Assert it's different.
  109. [FIRApp configureWithName:customAppName options:options];
  110. FIRApp *secondCustomApp = [FIRApp appNamed:customAppName];
  111. FIRDatabase *secondCustomDatabase = [FIRDatabase databaseForApp:secondCustomApp];
  112. XCTAssertNotNil(secondCustomDatabase);
  113. XCTAssertNotEqualObjects(customDatabase, secondCustomDatabase);
  114. }
  115. - (void)testReferenceWithPath {
  116. FIRDatabase *db = [self defaultDatabase];
  117. NSString *expectedURL = [NSString stringWithFormat:@"%@/foo", self.databaseURL];
  118. XCTAssertEqualObjects(expectedURL, [db referenceWithPath:@"foo"].URL);
  119. }
  120. - (void)testReferenceFromURLWithEmptyPath {
  121. FIRDatabaseReference *ref = [[self defaultDatabase] referenceFromURL:self.databaseURL];
  122. XCTAssertEqualObjects(self.databaseURL, ref.URL);
  123. }
  124. - (void)testReferenceFromURLWithPath {
  125. NSString *url = [NSString stringWithFormat:@"%@/foo/bar", self.databaseURL];
  126. FIRDatabaseReference *ref = [[self defaultDatabase] referenceFromURL:url];
  127. XCTAssertEqualObjects(url, ref.URL);
  128. }
  129. - (void)testReferenceFromURLWithWrongURL {
  130. NSString *url = [NSString stringWithFormat:@"%@/foo/bar", @"https://foobar.firebaseio.com"];
  131. XCTAssertThrows([[self defaultDatabase] referenceFromURL:url]);
  132. }
  133. - (void)testReferenceEqualityForFIRDatabase {
  134. FIRDatabase *db1 = [self databaseForURL:self.databaseURL name:@"db1"];
  135. FIRDatabase *db2 = [self databaseForURL:self.databaseURL name:@"db2"];
  136. FIRDatabase *altDb = [self databaseForURL:self.databaseURL name:@"altDb"];
  137. FIRDatabase *wrongHostDb = [self databaseForURL:@"http://tests.example.com"];
  138. FIRDatabaseReference *testRef1 = [db1 reference];
  139. FIRDatabaseReference *testRef2 = [db1 referenceWithPath:@"foo"];
  140. FIRDatabaseReference *testRef3 = [altDb reference];
  141. FIRDatabaseReference *testRef4 = [wrongHostDb reference];
  142. FIRDatabaseReference *testRef5 = [db2 reference];
  143. FIRDatabaseReference *testRef6 = [db2 reference];
  144. // Referential equality
  145. XCTAssertTrue(testRef1.database == testRef2.database);
  146. XCTAssertFalse(testRef1.database == testRef3.database);
  147. XCTAssertFalse(testRef1.database == testRef4.database);
  148. XCTAssertFalse(testRef1.database == testRef5.database);
  149. XCTAssertFalse(testRef1.database == testRef6.database);
  150. // references from same FIRDatabase same identical .database references.
  151. XCTAssertTrue(testRef5.database == testRef6.database);
  152. [db1 goOffline];
  153. [db2 goOffline];
  154. [altDb goOffline];
  155. [wrongHostDb goOffline];
  156. }
  157. - (FIRDatabaseReference *)rootRefWithEngine:(id<FStorageEngine>)engine name:(NSString *)name {
  158. FIRDatabaseConfig *config = [FTestHelpers configForName:name];
  159. config.persistenceEnabled = YES;
  160. config.forceStorageEngine = engine;
  161. return [[FTestHelpers databaseForConfig:config] reference];
  162. }
  163. - (void)testPurgeWritesPurgesAllWrites {
  164. FMockStorageEngine *engine = [[FMockStorageEngine alloc] init];
  165. FIRDatabaseReference *ref = [self rootRefWithEngine:engine name:@"purgeWritesPurgesAllWrites"];
  166. FIRDatabase *database = ref.database;
  167. [database goOffline];
  168. [[ref childByAutoId] setValue:@"test-value-1"];
  169. [[ref childByAutoId] setValue:@"test-value-2"];
  170. [[ref childByAutoId] setValue:@"test-value-3"];
  171. [[ref childByAutoId] setValue:@"test-value-4"];
  172. [self waitForEvents:ref];
  173. XCTAssertEqual(engine.userWrites.count, (NSUInteger)4);
  174. [database purgeOutstandingWrites];
  175. [self waitForEvents:ref];
  176. XCTAssertEqual(engine.userWrites.count, (NSUInteger)0);
  177. [database goOnline];
  178. }
  179. - (void)testPurgeWritesAreCanceledInOrder {
  180. FMockStorageEngine *engine = [[FMockStorageEngine alloc] init];
  181. FIRDatabaseReference *ref = [self rootRefWithEngine:engine name:@"purgeWritesAndCanceledInOrder"];
  182. FIRDatabase *database = ref.database;
  183. [database goOffline];
  184. NSMutableArray *order = [NSMutableArray array];
  185. [[ref childByAutoId] setValue:@"test-value-1"
  186. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  187. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  188. [order addObject:@"1"];
  189. }];
  190. [[ref childByAutoId] setValue:@"test-value-2"
  191. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  192. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  193. [order addObject:@"2"];
  194. }];
  195. [[ref childByAutoId] setValue:@"test-value-3"
  196. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  197. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  198. [order addObject:@"3"];
  199. }];
  200. [[ref childByAutoId] setValue:@"test-value-4"
  201. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  202. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  203. [order addObject:@"4"];
  204. }];
  205. [self waitForEvents:ref];
  206. XCTAssertEqual(engine.userWrites.count, (NSUInteger)4);
  207. [database purgeOutstandingWrites];
  208. [self waitForEvents:ref];
  209. XCTAssertEqual(engine.userWrites.count, (NSUInteger)0);
  210. XCTAssertEqualObjects(order, (@[ @"1", @"2", @"3", @"4" ]));
  211. [database goOnline];
  212. }
  213. - (void)testPurgeWritesCancelsOnDisconnects {
  214. FMockStorageEngine *engine = [[FMockStorageEngine alloc] init];
  215. FIRDatabaseReference *ref = [self rootRefWithEngine:engine
  216. name:@"purgeWritesCancelsOnDisconnects"];
  217. FIRDatabase *database = ref.database;
  218. [database goOffline];
  219. NSMutableArray *events = [NSMutableArray array];
  220. [[ref childByAutoId] onDisconnectSetValue:@"test-value-1"
  221. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  222. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  223. [events addObject:@"1"];
  224. }];
  225. [[ref childByAutoId] onDisconnectSetValue:@"test-value-2"
  226. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  227. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  228. [events addObject:@"2"];
  229. }];
  230. [self waitForEvents:ref];
  231. [database purgeOutstandingWrites];
  232. [self waitForEvents:ref];
  233. XCTAssertEqualObjects(events, (@[ @"1", @"2" ]));
  234. }
  235. - (void)testPurgeWritesReraisesEvents {
  236. FMockStorageEngine *engine = [[FMockStorageEngine alloc] init];
  237. FIRDatabaseReference *ref = [[self rootRefWithEngine:engine
  238. name:@"purgeWritesReraiseEvents"] childByAutoId];
  239. FIRDatabase *database = ref.database;
  240. [self waitForCompletionOf:ref
  241. setValue:@{@"foo" : @"foo-value", @"bar" : @{@"qux" : @"qux-value"}}];
  242. NSMutableArray *fooValues = [NSMutableArray array];
  243. NSMutableArray *barQuuValues = [NSMutableArray array];
  244. NSMutableArray *barQuxValues = [NSMutableArray array];
  245. NSMutableArray *cancelOrder = [NSMutableArray array];
  246. [[ref child:@"foo"] observeEventType:FIRDataEventTypeValue
  247. withBlock:^(FIRDataSnapshot *snapshot) {
  248. [fooValues addObject:snapshot.value];
  249. }];
  250. [[ref child:@"bar/quu"] observeEventType:FIRDataEventTypeValue
  251. withBlock:^(FIRDataSnapshot *snapshot) {
  252. [barQuuValues addObject:snapshot.value];
  253. }];
  254. [[ref child:@"bar/qux"] observeEventType:FIRDataEventTypeValue
  255. withBlock:^(FIRDataSnapshot *snapshot) {
  256. [barQuxValues addObject:snapshot.value];
  257. }];
  258. [database goOffline];
  259. [[ref child:@"foo"] setValue:@"new-foo-value"
  260. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  261. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  262. // This should be after we raised events
  263. XCTAssertEqualObjects(fooValues.lastObject, @"foo-value");
  264. [cancelOrder addObject:@"foo-1"];
  265. }];
  266. [[ref child:@"bar"] updateChildValues:@{@"quu" : @"quu-value", @"qux" : @"new-qux-value"}
  267. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  268. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  269. // This should be after we raised events
  270. XCTAssertEqualObjects(barQuxValues.lastObject, @"qux-value");
  271. XCTAssertEqualObjects(barQuuValues.lastObject, [NSNull null]);
  272. [cancelOrder addObject:@"bar"];
  273. }];
  274. [[ref child:@"foo"] setValue:@"newest-foo-value"
  275. withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
  276. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  277. // This should be after we raised events
  278. XCTAssertEqualObjects(fooValues.lastObject, @"foo-value");
  279. [cancelOrder addObject:@"foo-2"];
  280. }];
  281. [database purgeOutstandingWrites];
  282. [self waitForEvents:ref];
  283. XCTAssertEqualObjects(cancelOrder, (@[ @"foo-1", @"bar", @"foo-2" ]));
  284. XCTAssertEqualObjects(fooValues,
  285. (@[ @"foo-value", @"new-foo-value", @"newest-foo-value", @"foo-value" ]));
  286. XCTAssertEqualObjects(barQuuValues, (@[ [NSNull null], @"quu-value", [NSNull null] ]));
  287. XCTAssertEqualObjects(barQuxValues, (@[ @"qux-value", @"new-qux-value", @"qux-value" ]));
  288. [database goOnline];
  289. // Make sure we're back online and reconnected again
  290. [self waitForRoundTrip:ref];
  291. // No events should be reraised
  292. XCTAssertEqualObjects(cancelOrder, (@[ @"foo-1", @"bar", @"foo-2" ]));
  293. XCTAssertEqualObjects(fooValues,
  294. (@[ @"foo-value", @"new-foo-value", @"newest-foo-value", @"foo-value" ]));
  295. XCTAssertEqualObjects(barQuuValues, (@[ [NSNull null], @"quu-value", [NSNull null] ]));
  296. XCTAssertEqualObjects(barQuxValues, (@[ @"qux-value", @"new-qux-value", @"qux-value" ]));
  297. }
  298. - (void)testPurgeWritesCancelsTransactions {
  299. FMockStorageEngine *engine = [[FMockStorageEngine alloc] init];
  300. FIRDatabaseReference *ref =
  301. [[self rootRefWithEngine:engine name:@"purgeWritesCancelsTransactions"] childByAutoId];
  302. FIRDatabase *database = ref.database;
  303. NSMutableArray *events = [NSMutableArray array];
  304. [ref observeEventType:FIRDataEventTypeValue
  305. withBlock:^(FIRDataSnapshot *snapshot) {
  306. [events addObject:[NSString stringWithFormat:@"value-%@", snapshot.value]];
  307. }];
  308. // Make sure the first value event is fired
  309. [self waitForRoundTrip:ref];
  310. [database goOffline];
  311. [ref
  312. runTransactionBlock:^FIRTransactionResult *(FIRMutableData *currentData) {
  313. [currentData setValue:@"1"];
  314. return [FIRTransactionResult successWithValue:currentData];
  315. }
  316. andCompletionBlock:^(NSError *error, BOOL committed, FIRDataSnapshot *snapshot) {
  317. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  318. [events addObject:@"cancel-1"];
  319. }];
  320. [ref
  321. runTransactionBlock:^FIRTransactionResult *(FIRMutableData *currentData) {
  322. [currentData setValue:@"2"];
  323. return [FIRTransactionResult successWithValue:currentData];
  324. }
  325. andCompletionBlock:^(NSError *error, BOOL committed, FIRDataSnapshot *snapshot) {
  326. XCTAssertEqual(error.code, kFErrorCodeWriteCanceled);
  327. [events addObject:@"cancel-2"];
  328. }];
  329. [database purgeOutstandingWrites];
  330. [self waitForEvents:ref];
  331. // The order should really be cancel-1 then cancel-2, but meh, to difficult to implement
  332. // currently...
  333. XCTAssertEqualObjects(
  334. events,
  335. (@[ @"value-<null>", @"value-1", @"value-2", @"value-<null>", @"cancel-2", @"cancel-1" ]));
  336. }
  337. - (void)testPersistenceEnabled {
  338. id app = [[FIRFakeApp alloc] initWithName:@"testPersistenceEnabled" URL:self.databaseURL];
  339. FIRDatabase *database = [FIRDatabase databaseForApp:app];
  340. database.persistenceEnabled = YES;
  341. XCTAssertTrue(database.persistenceEnabled);
  342. // Just do a dummy observe that should get null added to the persistent cache.
  343. FIRDatabaseReference *ref = [[database reference] childByAutoId];
  344. [self waitForValueOf:ref toBe:[NSNull null]];
  345. // Now go offline and since null is cached offline, our observer should still complete.
  346. [database goOffline];
  347. [self waitForValueOf:ref toBe:[NSNull null]];
  348. }
  349. - (void)testPersistenceCacheSizeBytes {
  350. id app = [[FIRFakeApp alloc] initWithName:@"testPersistenceCacheSizeBytes" URL:self.databaseURL];
  351. FIRDatabase *database = [FIRDatabase databaseForApp:app];
  352. database.persistenceEnabled = YES;
  353. int oneMegabyte = 1 * 1024 * 1024;
  354. XCTAssertThrows([database setPersistenceCacheSizeBytes:1], @"Cache must be a least 1 MB.");
  355. XCTAssertThrows([database setPersistenceCacheSizeBytes:101 * oneMegabyte],
  356. @"Cache must be less than 100 MB.");
  357. database.persistenceCacheSizeBytes = 2 * oneMegabyte;
  358. XCTAssertEqual(2 * oneMegabyte, database.persistenceCacheSizeBytes);
  359. [database reference]; // Initialize database.
  360. XCTAssertThrows([database setPersistenceCacheSizeBytes:3 * oneMegabyte],
  361. @"Persistence can't be changed after initialization.");
  362. XCTAssertEqual(2 * oneMegabyte, database.persistenceCacheSizeBytes);
  363. }
  364. - (void)testCallbackQueue {
  365. id app = [[FIRFakeApp alloc] initWithName:@"testCallbackQueue" URL:self.databaseURL];
  366. FIRDatabase *database = [FIRDatabase databaseForApp:app];
  367. dispatch_queue_t callbackQueue = dispatch_queue_create("testCallbackQueue", NULL);
  368. database.callbackQueue = callbackQueue;
  369. XCTAssertEqual(callbackQueue, database.callbackQueue);
  370. __block BOOL done = NO;
  371. [database.reference.childByAutoId observeSingleEventOfType:FIRDataEventTypeValue
  372. withBlock:^(FIRDataSnapshot *snapshot) {
  373. if (@available(iOS 10.0, macOS 10.12, *)) {
  374. dispatch_assert_queue(callbackQueue);
  375. } else {
  376. NSAssert(YES, @"Test requires iOS 10");
  377. }
  378. done = YES;
  379. }];
  380. WAIT_FOR(done);
  381. [database goOffline];
  382. }
  383. - (FIRDatabase *)defaultDatabase {
  384. return [self databaseForURL:self.databaseURL];
  385. }
  386. - (FIRDatabase *)databaseForURL:(NSString *)url {
  387. NSString *name = [NSString stringWithFormat:@"url:%@", url];
  388. return [self databaseForURL:url name:name];
  389. }
  390. - (FIRDatabase *)databaseForURL:(NSString *)url name:(NSString *)name {
  391. NSString *defaultDatabaseURL = [NSString stringWithFormat:@"url:%@", self.databaseURL];
  392. if ([url isEqualToString:self.databaseURL] && [name isEqualToString:defaultDatabaseURL]) {
  393. // Use the default app for the default URL to avoid getting out of sync with FRepoManager
  394. // when calling ensureRepo during tests that don't create their own FIRFakeApp.
  395. return [FTestHelpers defaultDatabase];
  396. } else {
  397. id app = [[FIRFakeApp alloc] initWithName:name URL:url];
  398. return [FIRDatabase databaseForApp:app];
  399. }
  400. }
  401. @end