Files
firebase-ios-sdk/Example/Database/Tests/Integration/FEventTests.m
T
2017-05-15 12:27:07 -07:00

507 lines
17 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 "FEventTests.h"
#import "FTestHelpers.h"
#import "FTupleEventTypeString.h"
#import "FEventTester.h"
@implementation FEventTests
- (void) testInvalidEventType {
FIRDatabaseReference * f = [FTestHelpers getRandomNode];
XCTAssertThrows([f observeEventType:-4 withBlock:^(FIRDataSnapshot *s) {}], @"Invalid event type properly throws an error");
}
- (void) testWriteLeafExpectValueChanged {
FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
FIRDatabaseReference * writeNode = tuple.one;
FIRDatabaseReference * readNode = tuple.two;
__block BOOL done = NO;
[writeNode setValue:@1234 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
[super snapWaiter:readNode withBlock:^(FIRDataSnapshot *s) {
XCTAssertEqualObjects([s value], @1234, @"Proper value in snapshot");
}];
}
- (void) testWRiteLeafNodeThenExpectValueEvent {
FIRDatabaseReference * writeNode = [FTestHelpers getRandomNode];
[writeNode setValue:@42];
[super snapWaiter:writeNode withBlock:^(FIRDataSnapshot *s) {
XCTAssertEqualObjects([s value], @42, @"Proper value in snapshot");
}];
}
- (void) testWriteLeafNodeThenExpectChildAddedEventThenValueEvent {
FIRDatabaseReference * writeNode = [FTestHelpers getRandomNode];
[[writeNode child:@"foo"] setValue:@878787];
NSArray* lookingFor = @[
[[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeChildAdded withString:@"foo"],
[[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeValue withString:nil],
];
FEventTester* et = [[FEventTester alloc] initFrom:self];
[et addLookingFor:lookingFor];
[et wait];
[super snapWaiter:writeNode withBlock:^(FIRDataSnapshot *s) {
XCTAssertEqualObjects([[s childSnapshotForPath:@"foo"] value], @878787, @"Got proper value");
}];
}
- (void) testWriteTwoNestedLeafNodesChange {
}
- (void) testSetMultipleEventListenersOnSameNode {
FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
FIRDatabaseReference * writeNode = tuple.one;
FIRDatabaseReference * readNode = tuple.two;
[writeNode setValue:@42];
// two write nodes
FEventTester* et = [[FEventTester alloc] initFrom:self];
[et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeValue withString:nil] ]];
[et wait];
et = [[FEventTester alloc] initFrom:self];
[et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeValue withString:nil] ]];
[et wait];
// two read nodes
et = [[FEventTester alloc] initFrom:self];
[et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:readNode withEvent:FIRDataEventTypeValue withString:nil] ]];
[et wait];
et = [[FEventTester alloc] initFrom:self];
[et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:readNode withEvent:FIRDataEventTypeValue withString:nil] ]];
[et wait];
}
- (void) testUnsubscribeEventsAndConfirmThatEventsNoLongerFire {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
__block int numValueCB = 0;
FIRDatabaseHandle handle = [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *s) {
numValueCB = numValueCB + 1;
}];
// Set
for(int i = 0; i < 3; i++) {
[node setValue:[NSNumber numberWithInt:i]];
}
// bye
[node removeObserverWithHandle:handle];
// set again
for(int i = 10; i < 15; i++) {
[node setValue:[NSNumber numberWithInt:i]];
}
for(int i = 20; i < 25; i++) {
[node setValue:[NSNumber numberWithInt:i]];
}
// Should just be 3
[self waitUntil:^BOOL{
return numValueCB == 3;
}];
}
- (void) testCanWriteACompoundObjectAndGetMoreGranularEventsForIndividualChanges {
FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
FIRDatabaseReference * writeNode = tuple.one;
FIRDatabaseReference * readNode = tuple.two;
__block BOOL done = NO;
[writeNode setValue:@{@"a": @10, @"b": @20} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
done = YES;
}];
[self waitUntil:^BOOL{ return done; }];
NSArray* lookingForW = @[
[[FTupleEventTypeString alloc] initWithFirebase:[writeNode child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
[[FTupleEventTypeString alloc] initWithFirebase:[writeNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil],
];
NSArray* lookingForR = @[
[[FTupleEventTypeString alloc] initWithFirebase:[readNode child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
[[FTupleEventTypeString alloc] initWithFirebase:[readNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil],
];
FEventTester* etW = [[FEventTester alloc] initFrom:self];
[etW addLookingFor:lookingForW];
[etW wait];
FEventTester* etR = [[FEventTester alloc] initFrom:self];
[etR addLookingFor:lookingForR];
[etR wait];
// Modify compound but just change one of them
lookingForW = @[[[FTupleEventTypeString alloc] initWithFirebase:[writeNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil] ];
lookingForR = @[[[FTupleEventTypeString alloc] initWithFirebase:[readNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil] ];
[etW addLookingFor:lookingForW];
[etR addLookingFor:lookingForR];
[writeNode setValue:@{@"a": @10, @"b": @30}];
[etW wait];
[etR wait];
}
- (void) testValueEventIsFiredForEmptyNode {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
__block BOOL valueFired = NO;
[node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *s) {
XCTAssertTrue([[s value] isEqual:[NSNull null]], @"Value is properly nil");
valueFired = YES;
}];
[self waitUntil:^BOOL{
return valueFired;
}];
}
- (void) testCorrectEventsRaisedWhenLeafTurnsIntoInternalNode {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
NSMutableString* eventString = [[NSMutableString alloc] init];
[node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *s) {
if ([s hasChildren]) {
[eventString appendString:@", got children"];
}
else {
[eventString appendFormat:@", value %@", [s value]];
}
}];
[node observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *s) {
[eventString appendFormat:@", child_added %@", [s key]];
}];
[node setValue:@42];
[node setValue:@{@"a": @2}];
[node setValue:@84];
__block BOOL done = NO;
[node setValue:nil withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
XCTAssertEqualObjects(@", value 42, child_added a, got children, value 84, value <null>", eventString, @"Proper order seen");
}
- (void) testRegisteringCallbackMultipleTimesAndUnregistering {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
__block int changes = 0;
fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) { changes = changes + 1; };
FIRDatabaseHandle handle1 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
FIRDatabaseHandle handle2 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
FIRDatabaseHandle handle3 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
__block BOOL done = NO;
[node setValue:@42 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
done = NO;
XCTAssertTrue(changes == 3, @"Saw 3 callback events %d", changes);
[node removeObserverWithHandle:handle1];
[node setValue:@84 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
done = NO;
XCTAssertTrue(changes == 5, @"Saw 5 callback events %d", changes);
[node removeObserverWithHandle:handle2];
[node setValue:@168 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
done = NO;
XCTAssertTrue(changes == 6, @"Saw 6 callback events %d", changes);
[node removeObserverWithHandle:handle3];
[node setValue:@376 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
done = NO;
XCTAssertTrue(changes == 6, @"Saw 6 callback events %d", changes);
NSLog(@"callbacks: %d", changes);
}
- (void) testUnregisteringTheSameCallbackTooManyTimesDoesNothing {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) { };
FIRDatabaseHandle handle1 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
[node removeObserverWithHandle:handle1];
[node removeObserverWithHandle:handle1];
XCTAssertTrue(YES, @"Properly reached end of test without throwing errors.");
}
- (void) testOnceValueFiresExactlyOnce {
FIRDatabaseReference * path = [FTestHelpers getRandomNode];
__block BOOL firstCall = YES;
[path observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
XCTAssertTrue(firstCall, @"Properly saw first call");
firstCall = NO;
XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw node value");
}];
[path setValue:@42];
[path setValue:@84];
__block BOOL done = NO;
[path setValue:nil withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
}
- (void) testOnceChildAddedFiresExaclyOnce {
__block int badCount = 0;
// for(int i = 0; i < 100; i++) {
FIRDatabaseReference * path = [FTestHelpers getRandomNode];
__block BOOL firstCall = YES;
__block BOOL done = NO;
[path observeSingleEventOfType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
XCTAssertTrue(firstCall, @"Properly saw first call");
firstCall = NO;
XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw node value");
XCTAssertEqualObjects(@"foo", [snapshot key], @"Properly saw the first node");
if (![[snapshot value] isEqual:@42]) {
exit(-1);
badCount = badCount + 1;
}
done = YES;
}];
[[path child:@"foo"] setValue:@42];
[[path child:@"bar"] setValue:@84]; // XXX FIXME sometimes this event fires first
[[path child:@"foo"] setValue:@168];
// [path setValue:nil withCompletionBlock:^(BOOL status) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
// }
NSLog(@"BADCOUNT: %d", badCount);
}
- (void) testOnceValueFiresExacltyOnceEvenIfThereIsASetInsideCallback {
FIRDatabaseReference * path = [FTestHelpers getRandomNode];
__block BOOL firstCall = YES;
__block BOOL done = NO;
[path observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
XCTAssertTrue(firstCall, @"Properly saw first call");
if (firstCall) {
firstCall = NO;
XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw node value");
[path setValue:@43];
done = YES;
}
else {
XCTFail(@"Callback got called more than once.");
}
}];
[path setValue:@42];
[path setValue:@84];
[self waitUntil:^BOOL{ return done; }];
}
- (void) testOnceChildAddedFiresOnceEvenWithCompoundObject {
FIRDatabaseReference * path = [FTestHelpers getRandomNode];
__block BOOL firstCall = YES;
[path observeSingleEventOfType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
XCTAssertTrue(firstCall, @"Properly saw first call");
firstCall = NO;
XCTAssertEqualObjects(@84, [snapshot value], @"Properly saw node value");
XCTAssertEqualObjects(@"bar", [snapshot key], @"Properly saw the first node");
}];
[path setValue:@{@"foo": @42, @"bar": @84}];
__block BOOL done = NO;
[path setValue:nil withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
[self waitUntil:^BOOL{ return done; }];
}
- (void) testOnEmptyChildFires {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
__block BOOL done = NO;
[node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
}];
[[node child:@"test"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
XCTAssertTrue([[snapshot value] isEqual:[NSNull null]], @"Properly saw nil child node");
done = YES;
}];
[self waitUntil:^BOOL{ return done; }];
}
- (void) testOnEmptyChildEvenAfterParentIsSynched {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
__block BOOL parentDone = NO;
__block BOOL done = NO;
[node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
parentDone = YES;
}];
[self waitUntil:^BOOL{
return parentDone;
}];
[[node child:@"test"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
XCTAssertTrue([[snapshot value] isEqual:[NSNull null]], @"Child is properly nil");
done = YES;
}];
// This test really isn't in the same spirit as the JS test; we can't currently make sure that the test fires right away since the ON and callback are async
[self waitUntil:^BOOL{
return done;
}];
XCTAssertTrue(done, @"Done fired.");
}
- (void) testEventsAreRaisedChildRemovedChildAddedChildMoved {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
NSMutableArray* events = [[NSMutableArray alloc] init];
[node observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snap) {
[events addObject:[NSString stringWithFormat:@"added %@", [snap key]]];
}];
[node observeEventType:FIRDataEventTypeChildRemoved withBlock:^(FIRDataSnapshot *snap) {
[events addObject:[NSString stringWithFormat:@"removed %@", [snap key]]];
}];
[node observeEventType:FIRDataEventTypeChildMoved withBlock:^(FIRDataSnapshot *snap) {
[events addObject:[NSString stringWithFormat:@"moved %@", [snap key]]];
}];
__block BOOL done = NO;
[node setValue:@{
@"a": @{@".value": @1, @".priority": @0 },
@"b": @{@".value": @1, @".priority": @1 },
@"c": @{@".value": @1, @".priority": @2 },
@"d": @{@".value": @1, @".priority": @3 },
@"e": @{@".value": @1, @".priority": @4 },
@"f": @{@".value": @1, @".priority": @5 },
} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
done = YES;
}];
[self waitUntil:^BOOL{
return done;
}];
[events removeAllObjects];
done = NO;
[node setValue:@{
@"a": @{@".value": @1, @".priority": @5 },
@"aa": @{@".value": @1, @".priority": @0 },
@"b": @{@".value": @1, @".priority": @1 },
@"bb": @{@".value": @1, @".priority": @2 },
@"d": @{@".value": @1, @".priority": @3 },
@"e": @{@".value": @1, @".priority": @6 },
}
withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
done = YES;
}
];
[self waitUntil:^BOOL{
return done;
}];
XCTAssertEqualObjects(@"removed c, removed f, added aa, added bb, moved a, moved e", [events componentsJoinedByString:@", "], @"Got expected results");
}
- (void) testIntegerToDoubleConversions {
FIRDatabaseReference * node = [FTestHelpers getRandomNode];
NSMutableArray<NSString *>* events = [[NSMutableArray alloc] init];
[node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snap) {
[events addObject:[NSString stringWithFormat:@"value %@", [snap value]]];
}];
for(NSNumber *number in @[@1, @1.0, @1, @1.1]) {
[self waitForCompletionOf:node setValue:number];
}
XCTAssertEqualObjects(@"value 1, value 1.1", [events componentsJoinedByString:@", "],
@"Got expected results");
}
- (void) testEventsAreRaisedProperlyWithOnQueryLimits {
// xxx impl query
}
@end