mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
* Register Database with Interop
+ Add AuthInterop dependency
+ Have Database register with Interop component container
+ Add weak dependency on Auth
~ Cleaned up imports
* Use Interop for Auth token fetching
+ Use macro to get auth component
~ Change `getTokenForcingRefresh:withCallback:` call to use Interop component version of Auth
~ Clean up imports
* Implement necessary protocols
+ Added FIRComponentRegistrant and FIRDatabaseNilProtocol to FIRDatabase
* Squash of my previous local commits for Database Interop
Register Database with Interop:
+ Add AuthInterop dependency
+ Have Database register with Interop component container
+ Add weak dependency on Auth
~ Cleaned up imports
Use Interop for Auth token fetching:
+ Use macro to get auth component
~ Change `getTokenForcingRefresh:withCallback:` call to use Interop component version of Auth
~ Clean up imports
Implement necessary protocols:
+ Added FIRComponentRegistrant and FIRDatabaseNilProtocol to FIRDatabase
Clean up Database tests:
- Removed all unnecessary header files
~ Ran style.sh across all the tests
Cleaned Up project file:
Some header removals were missed in the last commit.
Sorted some test files
Fix Database Fake App Tests:
+ Added container property
+ Added an Auth fake in the container
+ Added the Shared utils files to the necessary targets
+ Added a missing XCTest reference in a test that didn't compile for me
* Revert "Squash of my previous local commits for Database Interop"
This reverts commit c0d0421237.
* Cleaned Up project file
Some header removals were missed in the last commit.
* Sorted some test files
* Fix Database Fake App Tests
+ Added container property
+ Added an Auth fake in the container
+ Added the Shared utils files to the necessary targets
+ Added a missing XCTest reference in a test that didn't compile for me
* PR Feedback Changes
+ Created new FIRDatabaseComponent class to encapsulate instance creation
+ Updated FAuthTokenProvider to only use an auth instance rather than an app.
* PR Feedback Follow-Up
- Removed FIRDatabase registration code
* pod deintegrate
* Move instance management
Somes tests may still be out of date.
* Fix Auth integration test
* pod deintegrate -- again
* PR Feedback
* PR Feedback
Added the FIRComponentLifecycleMaintainer protocol to FIRDatabaseComponent
* Update Firebase/Database/Api/FIRDatabaseComponent.m
Missed some small changes
* Get integration tests compiling
* Fix some tests
* Fixed more tests
Component needs to be cacheable in order to get the appWIllBeDeleted callback.
* Update target memberships
* Revert project file changes
* Add FIRAuthInteropFake for broken targets
* PR feedback
* Spacing and Style
* Moved `instances` to ivar
* Simplify FIRDatabaseDictionary
It's now keyed on the URL with the app being implied since each app will get its own `FIRDatabaseComponent`
* Fix Database Integration Tests
Have the FakeApp cache DB instances
Use the Full host/URL path to cache DB instances
Simplified shared scheme
```
Test Suite 'Database_IntegrationTests_iOS.xctest' passed at 2018-11-20 07:09:30.520.
Executed 326 tests, with 0 failures (0 unexpected) in 66.251 (66.528) seconds
Test Suite 'All tests' passed at 2018-11-20 07:09:30.522.
Executed 326 tests, with 0 failures (0 unexpected) in 66.251 (66.530) seconds
```
* Clarify defaultApp use
608 lines
22 KiB
Objective-C
608 lines
22 KiB
Objective-C
/*
|
|
* Copyright 2017 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 "FRealtime.h"
|
|
#import "FTupleFirebase.h"
|
|
#import "FRepoManager.h"
|
|
#import "FUtilities.h"
|
|
#import "FParsedUrl.h"
|
|
#import "FIRDatabaseConfig_Private.h"
|
|
#import "FTestHelpers.h"
|
|
|
|
@implementation FRealtime
|
|
|
|
- (void) testUrlParsing {
|
|
FParsedUrl* parsed = [FUtilities parseUrl:@"http://www.example.com:9000"];
|
|
XCTAssertTrue([[parsed.path description] isEqualToString:@"/"], @"Got correct path");
|
|
XCTAssertTrue([parsed.repoInfo.host isEqualToString:@"www.example.com:9000"], @"Got correct host");
|
|
XCTAssertTrue([parsed.repoInfo.internalHost isEqualToString:@"www.example.com:9000"], @"Got correct host");
|
|
XCTAssertFalse(parsed.repoInfo.secure, @"Should not be secure, there's a port");
|
|
|
|
parsed = [FUtilities parseUrl:@"http://www.firebaseio.com/foo/bar"];
|
|
XCTAssertTrue([[parsed.path description] isEqualToString:@"/foo/bar"], @"Got correct path");
|
|
XCTAssertTrue([parsed.repoInfo.host isEqualToString:@"www.firebaseio.com"], @"Got correct host");
|
|
XCTAssertTrue([parsed.repoInfo.internalHost isEqualToString:@"www.firebaseio.com"], @"Got correct host");
|
|
XCTAssertTrue(parsed.repoInfo.secure, @"Should be secure, there's no port");
|
|
}
|
|
|
|
- (void) testCachingRedirects {
|
|
NSString* host = @"host.example.com";
|
|
NSString* host2 = @"host2.example.com";
|
|
NSString* internalHost = @"internal.example.com";
|
|
NSString* internalHost2 = @"internal2.example.com";
|
|
|
|
// Set host on first repo info
|
|
FRepoInfo* repoInfo = [[FRepoInfo alloc] initWithHost:host isSecure:YES withNamespace:host];
|
|
XCTAssertTrue([repoInfo.host isEqualToString:host], @"Got correct host");
|
|
XCTAssertTrue([repoInfo.internalHost isEqualToString:host], @"Got correct host");
|
|
|
|
// Set internal host on first repo info
|
|
repoInfo.internalHost = internalHost;
|
|
XCTAssertTrue([repoInfo.host isEqualToString:host], @"Got correct host");
|
|
XCTAssertTrue([repoInfo.internalHost isEqualToString:internalHost], @"Got correct host");
|
|
|
|
// Set up a second unrelated repo info to make sure caching is keyspaced properly
|
|
FRepoInfo* repoInfo2 = [[FRepoInfo alloc] initWithHost:host2 isSecure:YES withNamespace:host2];
|
|
XCTAssertTrue([repoInfo2.host isEqualToString:host2], @"Got correct host");
|
|
XCTAssertTrue([repoInfo2.internalHost isEqualToString:host2], @"Got correct host");
|
|
|
|
repoInfo2.internalHost = internalHost2;
|
|
XCTAssertTrue([repoInfo2.internalHost isEqualToString:internalHost2], @"Got correct host");
|
|
|
|
// Setting host on this repo info should also set the right internal host
|
|
FRepoInfo* repoInfoCached = [[FRepoInfo alloc] initWithHost:host isSecure:YES withNamespace:host];
|
|
XCTAssertTrue([repoInfoCached.host isEqualToString:host], @"Got correct host");
|
|
XCTAssertTrue([repoInfoCached.internalHost isEqualToString:internalHost], @"Got correct host");
|
|
|
|
[repoInfo clearInternalHostCache];
|
|
[repoInfo2 clearInternalHostCache];
|
|
[repoInfoCached clearInternalHostCache];
|
|
|
|
XCTAssertTrue([repoInfo.internalHost isEqualToString:host], @"Got correct host");
|
|
XCTAssertTrue([repoInfo2.internalHost isEqualToString:host2], @"Got correct host");
|
|
XCTAssertTrue([repoInfoCached.internalHost isEqualToString:host], @"Got correct host");
|
|
}
|
|
|
|
- (void) testOnDisconnectSetWorks {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"];
|
|
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key];
|
|
|
|
__block NSNumber* readValue = @0;
|
|
__block NSNumber* writeValue = @0;
|
|
[[reader child:@"disconnected"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSNumber *val = [snapshot value];
|
|
if (![val isEqual:[NSNull null]]) {
|
|
readValue = val;
|
|
}
|
|
}];
|
|
|
|
[[writer child:@"disconnected"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
id val = [snapshot value];
|
|
if (val != [NSNull null]) {
|
|
writeValue = val;
|
|
}
|
|
}];
|
|
|
|
[writer child:@"hello"];
|
|
|
|
__block BOOL ready = NO;
|
|
[[writer child:@"disconnected"] onDisconnectSetValue:@1 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref){
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
|
|
[writer child:@"s"];
|
|
|
|
ready = NO;
|
|
[[writer child:@"disconnected"] onDisconnectSetValue:@2 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref){
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return [@2 isEqualToNumber:readValue] && [@2 isEqualToNumber:writeValue];
|
|
}];
|
|
|
|
[FRepoManager interrupt:readerCfg];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
[FRepoManager disposeRepos:readerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectSetWithPriorityWorks {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"];
|
|
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key];
|
|
|
|
__block BOOL sawNewValue = NO;
|
|
__block BOOL writerSawNewValue = NO;
|
|
[[reader child:@"disconnected"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
id val = snapshot.value;
|
|
id pri = snapshot.priority;
|
|
if (val != [NSNull null] && pri != [NSNull null]) {
|
|
sawNewValue = [(NSNumber *) val boolValue] && [pri isEqualToString:@"abcd"];
|
|
}
|
|
}];
|
|
|
|
[[writer child:@"disconnected"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
id val = [snapshot value];
|
|
id pri = snapshot.priority;
|
|
if (val != [NSNull null] && pri != [NSNull null]) {
|
|
writerSawNewValue = [(NSNumber *) val boolValue] && [pri isEqualToString:@"abcd"];
|
|
}
|
|
}];
|
|
|
|
__block BOOL ready = NO;
|
|
[[writer child:@"disconnected"] onDisconnectSetValue:@YES andPriority:@"abcd" withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return sawNewValue && writerSawNewValue;
|
|
}];
|
|
|
|
[FRepoManager interrupt:readerCfg];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
[FRepoManager disposeRepos:readerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectRemoveWorks {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"];
|
|
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key];
|
|
|
|
__block BOOL ready = NO;
|
|
[[writer child:@"foo"] setValue:@"bar" withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
|
|
__block BOOL sawRemove = NO;
|
|
__block BOOL writerSawRemove = NO;
|
|
[[reader child:@"foo"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
sawRemove = [[NSNull null] isEqual:snapshot.value];
|
|
}];
|
|
|
|
[[writer child:@"foo"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
writerSawRemove = [[NSNull null] isEqual:snapshot.value];
|
|
}];
|
|
|
|
ready = NO;
|
|
[[writer child:@"foo"] onDisconnectRemoveValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return sawRemove && writerSawRemove;
|
|
}];
|
|
|
|
[FRepoManager interrupt:readerCfg];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
[FRepoManager disposeRepos:readerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectUpdateWorks {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"];
|
|
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key];
|
|
|
|
[self waitForCompletionOf:[writer child:@"foo"] setValue:@{@"bar": @"a", @"baz": @"b"}];
|
|
|
|
__block BOOL sawNewValue = NO;
|
|
__block BOOL writerSawNewValue = NO;
|
|
[[reader child:@"foo"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSDictionary *val = [snapshot value];
|
|
if (val) {
|
|
sawNewValue = [@{@"bar" : @"a", @"baz" : @"c", @"bat" : @"d"} isEqualToDictionary:val];
|
|
}
|
|
}];
|
|
|
|
[[writer child:@"foo"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSDictionary *val = [snapshot value];
|
|
if (val) {
|
|
writerSawNewValue = [@{@"bar" : @"a", @"baz" : @"c", @"bat" : @"d"} isEqualToDictionary:val];
|
|
}
|
|
}];
|
|
|
|
__block BOOL ready = NO;
|
|
[[writer child:@"foo"] onDisconnectUpdateChildValues:@{@"baz": @"c", @"bat": @"d"} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return sawNewValue && writerSawNewValue;
|
|
}];
|
|
|
|
[FRepoManager interrupt:readerCfg];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
[FRepoManager disposeRepos:readerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectTriggersSingleLocalValueEventForWriter {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
|
|
__block int calls = 0;
|
|
[writer observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
calls++;
|
|
if (calls == 2) {
|
|
// second call, verify the data
|
|
NSDictionary *val = [snapshot value];
|
|
NSDictionary *expected = @{@"foo" : @{@"bar" : @"a", @"bam" : @"c"}};
|
|
XCTAssertTrue([val isEqualToDictionary:expected], @"Got all of the updates in one");
|
|
} else if (calls > 2) {
|
|
XCTFail(@"Extra calls");
|
|
}
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 1;
|
|
}];
|
|
|
|
__block BOOL done = NO;
|
|
FIRDatabaseReference * child = [writer child:@"foo"];
|
|
[child onDisconnectSetValue:@{@"bar": @"a", @"baz": @"b"}];
|
|
[child onDisconnectUpdateChildValues:@{@"bam": @"c"}];
|
|
[[child child:@"baz"] onDisconnectRemoveValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
done = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return done;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 2;
|
|
}];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectTriggersSingleLocalValueEventForReader {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseReference * reader = [FTestHelpers getRandomNode];
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] child:reader.key];
|
|
|
|
__block int calls = 0;
|
|
[reader observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
calls++;
|
|
if (calls == 2) {
|
|
// second call, verify the data
|
|
NSDictionary *val = [snapshot value];
|
|
NSDictionary *expected = @{@"foo" : @{@"bar" : @"a", @"bam" : @"c"}};
|
|
XCTAssertTrue([val isEqualToDictionary:expected], @"Got all of the updates in one");
|
|
} else if (calls > 2) {
|
|
XCTFail(@"Extra calls");
|
|
}
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 1;
|
|
}];
|
|
|
|
__block BOOL done = NO;
|
|
FIRDatabaseReference * child = [writer child:@"foo"];
|
|
[child onDisconnectSetValue:@{@"bar": @"a", @"baz": @"b"}];
|
|
[child onDisconnectUpdateChildValues:@{@"bam": @"c"}];
|
|
[[child child:@"baz"] onDisconnectRemoveValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
done = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return done;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 2;
|
|
}];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectTriggersSingleLocalValueEventForWriterWithQuery {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
|
|
__block int calls = 0;
|
|
[[[writer child:@"foo"] queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
calls++;
|
|
if (calls == 2) {
|
|
// second call, verify the data
|
|
NSDictionary *val = [snapshot value];
|
|
NSDictionary *expected = @{@"bar" : @"a", @"bam" : @"c"};
|
|
XCTAssertTrue([val isEqualToDictionary:expected], @"Got all of the updates in one");
|
|
} else if (calls > 2) {
|
|
XCTFail(@"Extra calls");
|
|
}
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 1;
|
|
}];
|
|
|
|
__block BOOL done = NO;
|
|
FIRDatabaseReference * child = [writer child:@"foo"];
|
|
[child onDisconnectSetValue:@{@"bar": @"a", @"baz": @"b"}];
|
|
[child onDisconnectUpdateChildValues:@{@"bam": @"c"}];
|
|
[[child child:@"baz"] onDisconnectRemoveValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
done = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return done;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 2;
|
|
}];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectTriggersSingleLocalValueEventForReaderWithQuery {
|
|
FIRDatabaseReference * reader = [FTestHelpers getRandomNode];
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] child:reader.key];
|
|
|
|
__block int calls = 0;
|
|
[[[reader child:@"foo"] queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
calls++;
|
|
XCTAssertTrue([snapshot.key isEqualToString:@"foo"], @"Got the right snapshot");
|
|
if (calls == 2) {
|
|
// second call, verify the data
|
|
NSDictionary *val = [snapshot value];
|
|
NSDictionary *expected = @{@"bar" : @"a", @"bam" : @"c"};
|
|
XCTAssertTrue([val isEqualToDictionary:expected], @"Got all of the updates in one");
|
|
} else if (calls > 2) {
|
|
XCTFail(@"Extra calls");
|
|
}
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 1;
|
|
}];
|
|
|
|
__block BOOL done = NO;
|
|
FIRDatabaseReference * child = [writer child:@"foo"];
|
|
[child onDisconnectSetValue:@{@"bar": @"a", @"baz": @"b"}];
|
|
[child onDisconnectUpdateChildValues:@{@"bam": @"c"}];
|
|
[[child child:@"baz"] onDisconnectRemoveValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
done = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return done;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return calls == 2;
|
|
}];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectDeepMergeTriggersOnlyOneValueEventForReaderWithQuery {
|
|
FIRDatabaseReference * reader = [FTestHelpers getRandomNode];
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
|
|
__block BOOL done = NO;
|
|
NSDictionary* toSet = @{@"a": @1, @"b": @{@"c": @YES, @"d": @"scalar", @"e": @{@"f": @"hooray"}}};
|
|
[writer setValue:toSet];
|
|
[[writer child:@"a"] onDisconnectSetValue:@2];
|
|
[[writer child:@"b/d"] onDisconnectRemoveValueWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
done = YES;
|
|
}];
|
|
|
|
WAIT_FOR(done);
|
|
|
|
__block int count = 2;
|
|
[[reader queryLimitedToLast:3] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
count++;
|
|
if (count == 1) {
|
|
// Loaded the data, kill the writer connection
|
|
[FRepoManager interrupt:writerCfg];
|
|
} else if (count == 2) {
|
|
NSDictionary *expected = @{@"a" : @2, @"b" : @{@"c" : @YES, @"e" : @{@"f" : @"hooray"}}};
|
|
XCTAssertTrue([snapshot.value isEqualToDictionary:expected], @"Should see complete new snapshot");
|
|
} else {
|
|
XCTFail(@"Too many calls");
|
|
}
|
|
}];
|
|
|
|
WAIT_FOR(count == 2);
|
|
|
|
// cleanup
|
|
[reader removeAllObservers];
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
}
|
|
|
|
|
|
- (void) testOnDisconnectCancelWorks {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseConfig *readerCfg = [FTestHelpers configForName:@"reader"];
|
|
|
|
FIRDatabaseReference * writer = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
FIRDatabaseReference * reader = [[[FIRDatabaseReference alloc] initWithConfig:readerCfg] child:writer.key];
|
|
|
|
__block BOOL ready = NO;
|
|
[[writer child:@"foo"] setValue:@{@"bar": @"a", @"baz": @"b"} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
|
|
__block BOOL sawNewValue = NO;
|
|
__block BOOL writerSawNewValue = NO;
|
|
[[reader child:@"foo"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSDictionary *val = [snapshot value];
|
|
if (val) {
|
|
sawNewValue = [@{@"bar" : @"a", @"baz" : @"b", @"bat" : @"d"} isEqualToDictionary:val];
|
|
}
|
|
}];
|
|
|
|
[[writer child:@"foo"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSDictionary *val = [snapshot value];
|
|
if (val) {
|
|
writerSawNewValue = [@{@"bar" : @"a", @"baz" : @"b", @"bat" : @"d"} isEqualToDictionary:val];
|
|
}
|
|
}];
|
|
|
|
ready = NO;
|
|
[[writer child:@"foo"] onDisconnectUpdateChildValues:@{@"baz": @"c", @"bat": @"d"}];
|
|
[[writer child:@"foo/baz"] cancelDisconnectOperationsWithCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
ready = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return ready;
|
|
}];
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return sawNewValue && writerSawNewValue;
|
|
}];
|
|
|
|
[FRepoManager interrupt:readerCfg];
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
[FRepoManager disposeRepos:readerCfg];
|
|
}
|
|
|
|
- (void) testOnDisconnectWithServerValuesWithLocalEvents {
|
|
FIRDatabaseConfig *writerCfg = [FTestHelpers configForName:@"writer"];
|
|
FIRDatabaseReference * node = [[[FIRDatabaseReference alloc] initWithConfig:writerCfg] childByAutoId];
|
|
|
|
__block FIRDataSnapshot *snap = nil;
|
|
[node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
snap = snapshot;
|
|
}];
|
|
|
|
NSDictionary* data = @{
|
|
@"a": @1,
|
|
@"b": @{
|
|
@".value": [FIRServerValue timestamp],
|
|
@".priority": [FIRServerValue timestamp]
|
|
}
|
|
};
|
|
|
|
__block BOOL done = NO;
|
|
[node onDisconnectSetValue:data andPriority:[FIRServerValue timestamp] withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
done = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return done;
|
|
}];
|
|
|
|
done = NO;
|
|
|
|
[node onDisconnectUpdateChildValues:@{ @"a": [FIRServerValue timestamp], @"c": [FIRServerValue timestamp] } withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
|
|
done = YES;
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return done;
|
|
}];
|
|
|
|
done = NO;
|
|
|
|
[FRepoManager interrupt:writerCfg];
|
|
|
|
[self waitUntil:^BOOL{
|
|
if ([snap value] != [NSNull null]) {
|
|
NSDictionary* val = [snap value];
|
|
done = (val[@"a"] && val[@"b"] && val[@"c"]);
|
|
}
|
|
return done;
|
|
}];
|
|
|
|
NSDictionary* value = [snap value];
|
|
NSNumber* now = [NSNumber numberWithDouble:round([[NSDate date] timeIntervalSince1970]*1000)];
|
|
NSNumber* timestamp = [snap priority];
|
|
XCTAssertTrue([[snap priority] isKindOfClass:[NSNumber class]], @"Should get back number");
|
|
XCTAssertTrue([now doubleValue] - [timestamp doubleValue] < 2000, @"Number should be no more than 2 seconds ago");
|
|
XCTAssertEqualObjects([snap priority], [value objectForKey:@"a"], @"Should get back matching ServerValue.TIMESTAMP");
|
|
XCTAssertEqualObjects([snap priority], [value objectForKey:@"b"], @"Should get back matching ServerValue.TIMESTAMP");
|
|
XCTAssertEqualObjects([snap priority], [[snap childSnapshotForPath:@"b"] priority], @"Should get back matching ServerValue.TIMESTAMP");
|
|
XCTAssertEqualObjects([NSNull null], [[snap childSnapshotForPath:@"d"] value], @"Should get null for cancelled child");
|
|
|
|
// cleanup
|
|
[FRepoManager disposeRepos:writerCfg];
|
|
}
|
|
|
|
@end
|