aboutsummaryrefslogtreecommitdiffhomepage
path: root/Example/Database/Tests/Integration/FEventTests.m
diff options
context:
space:
mode:
Diffstat (limited to 'Example/Database/Tests/Integration/FEventTests.m')
-rw-r--r--Example/Database/Tests/Integration/FEventTests.m506
1 files changed, 506 insertions, 0 deletions
diff --git a/Example/Database/Tests/Integration/FEventTests.m b/Example/Database/Tests/Integration/FEventTests.m
new file mode 100644
index 0000000..8b11e9d
--- /dev/null
+++ b/Example/Database/Tests/Integration/FEventTests.m
@@ -0,0 +1,506 @@
+/*
+ * 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