FEventTests.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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 "FEventTests.h"
  17. #import "FTestHelpers.h"
  18. #import "FTupleEventTypeString.h"
  19. #import "FEventTester.h"
  20. @implementation FEventTests
  21. - (void) testInvalidEventType {
  22. FIRDatabaseReference * f = [FTestHelpers getRandomNode];
  23. XCTAssertThrows([f observeEventType:-4 withBlock:^(FIRDataSnapshot *s) {}], @"Invalid event type properly throws an error");
  24. }
  25. - (void) testWriteLeafExpectValueChanged {
  26. FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
  27. FIRDatabaseReference * writeNode = tuple.one;
  28. FIRDatabaseReference * readNode = tuple.two;
  29. __block BOOL done = NO;
  30. [writeNode setValue:@1234 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  31. [self waitUntil:^BOOL{ return done; }];
  32. [super snapWaiter:readNode withBlock:^(FIRDataSnapshot *s) {
  33. XCTAssertEqualObjects([s value], @1234, @"Proper value in snapshot");
  34. }];
  35. }
  36. - (void) testWRiteLeafNodeThenExpectValueEvent {
  37. FIRDatabaseReference * writeNode = [FTestHelpers getRandomNode];
  38. [writeNode setValue:@42];
  39. [super snapWaiter:writeNode withBlock:^(FIRDataSnapshot *s) {
  40. XCTAssertEqualObjects([s value], @42, @"Proper value in snapshot");
  41. }];
  42. }
  43. - (void) testWriteLeafNodeThenExpectChildAddedEventThenValueEvent {
  44. FIRDatabaseReference * writeNode = [FTestHelpers getRandomNode];
  45. [[writeNode child:@"foo"] setValue:@878787];
  46. NSArray* lookingFor = @[
  47. [[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeChildAdded withString:@"foo"],
  48. [[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeValue withString:nil],
  49. ];
  50. FEventTester* et = [[FEventTester alloc] initFrom:self];
  51. [et addLookingFor:lookingFor];
  52. [et wait];
  53. [super snapWaiter:writeNode withBlock:^(FIRDataSnapshot *s) {
  54. XCTAssertEqualObjects([[s childSnapshotForPath:@"foo"] value], @878787, @"Got proper value");
  55. }];
  56. }
  57. - (void) testWriteTwoNestedLeafNodesChange {
  58. }
  59. - (void) testSetMultipleEventListenersOnSameNode {
  60. FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
  61. FIRDatabaseReference * writeNode = tuple.one;
  62. FIRDatabaseReference * readNode = tuple.two;
  63. [writeNode setValue:@42];
  64. // two write nodes
  65. FEventTester* et = [[FEventTester alloc] initFrom:self];
  66. [et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeValue withString:nil] ]];
  67. [et wait];
  68. et = [[FEventTester alloc] initFrom:self];
  69. [et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:writeNode withEvent:FIRDataEventTypeValue withString:nil] ]];
  70. [et wait];
  71. // two read nodes
  72. et = [[FEventTester alloc] initFrom:self];
  73. [et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:readNode withEvent:FIRDataEventTypeValue withString:nil] ]];
  74. [et wait];
  75. et = [[FEventTester alloc] initFrom:self];
  76. [et addLookingFor:@[[[FTupleEventTypeString alloc] initWithFirebase:readNode withEvent:FIRDataEventTypeValue withString:nil] ]];
  77. [et wait];
  78. }
  79. - (void) testUnsubscribeEventsAndConfirmThatEventsNoLongerFire {
  80. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  81. __block int numValueCB = 0;
  82. FIRDatabaseHandle handle = [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *s) {
  83. numValueCB = numValueCB + 1;
  84. }];
  85. // Set
  86. for(int i = 0; i < 3; i++) {
  87. [node setValue:[NSNumber numberWithInt:i]];
  88. }
  89. // bye
  90. [node removeObserverWithHandle:handle];
  91. // set again
  92. for(int i = 10; i < 15; i++) {
  93. [node setValue:[NSNumber numberWithInt:i]];
  94. }
  95. for(int i = 20; i < 25; i++) {
  96. [node setValue:[NSNumber numberWithInt:i]];
  97. }
  98. // Should just be 3
  99. [self waitUntil:^BOOL{
  100. return numValueCB == 3;
  101. }];
  102. }
  103. - (void) testCanWriteACompoundObjectAndGetMoreGranularEventsForIndividualChanges {
  104. FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
  105. FIRDatabaseReference * writeNode = tuple.one;
  106. FIRDatabaseReference * readNode = tuple.two;
  107. __block BOOL done = NO;
  108. [writeNode setValue:@{@"a": @10, @"b": @20} withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  109. done = YES;
  110. }];
  111. [self waitUntil:^BOOL{ return done; }];
  112. NSArray* lookingForW = @[
  113. [[FTupleEventTypeString alloc] initWithFirebase:[writeNode child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  114. [[FTupleEventTypeString alloc] initWithFirebase:[writeNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil],
  115. ];
  116. NSArray* lookingForR = @[
  117. [[FTupleEventTypeString alloc] initWithFirebase:[readNode child:@"a"] withEvent:FIRDataEventTypeValue withString:nil],
  118. [[FTupleEventTypeString alloc] initWithFirebase:[readNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil],
  119. ];
  120. FEventTester* etW = [[FEventTester alloc] initFrom:self];
  121. [etW addLookingFor:lookingForW];
  122. [etW wait];
  123. FEventTester* etR = [[FEventTester alloc] initFrom:self];
  124. [etR addLookingFor:lookingForR];
  125. [etR wait];
  126. // Modify compound but just change one of them
  127. lookingForW = @[[[FTupleEventTypeString alloc] initWithFirebase:[writeNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil] ];
  128. lookingForR = @[[[FTupleEventTypeString alloc] initWithFirebase:[readNode child:@"b"] withEvent:FIRDataEventTypeValue withString:nil] ];
  129. [etW addLookingFor:lookingForW];
  130. [etR addLookingFor:lookingForR];
  131. [writeNode setValue:@{@"a": @10, @"b": @30}];
  132. [etW wait];
  133. [etR wait];
  134. }
  135. - (void) testValueEventIsFiredForEmptyNode {
  136. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  137. __block BOOL valueFired = NO;
  138. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *s) {
  139. XCTAssertTrue([[s value] isEqual:[NSNull null]], @"Value is properly nil");
  140. valueFired = YES;
  141. }];
  142. [self waitUntil:^BOOL{
  143. return valueFired;
  144. }];
  145. }
  146. - (void) testCorrectEventsRaisedWhenLeafTurnsIntoInternalNode {
  147. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  148. NSMutableString* eventString = [[NSMutableString alloc] init];
  149. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *s) {
  150. if ([s hasChildren]) {
  151. [eventString appendString:@", got children"];
  152. }
  153. else {
  154. [eventString appendFormat:@", value %@", [s value]];
  155. }
  156. }];
  157. [node observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *s) {
  158. [eventString appendFormat:@", child_added %@", [s key]];
  159. }];
  160. [node setValue:@42];
  161. [node setValue:@{@"a": @2}];
  162. [node setValue:@84];
  163. __block BOOL done = NO;
  164. [node setValue:nil withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  165. [self waitUntil:^BOOL{ return done; }];
  166. XCTAssertEqualObjects(@", value 42, child_added a, got children, value 84, value <null>", eventString, @"Proper order seen");
  167. }
  168. - (void) testRegisteringCallbackMultipleTimesAndUnregistering {
  169. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  170. __block int changes = 0;
  171. fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) { changes = changes + 1; };
  172. FIRDatabaseHandle handle1 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
  173. FIRDatabaseHandle handle2 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
  174. FIRDatabaseHandle handle3 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
  175. __block BOOL done = NO;
  176. [node setValue:@42 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  177. [self waitUntil:^BOOL{ return done; }];
  178. done = NO;
  179. XCTAssertTrue(changes == 3, @"Saw 3 callback events %d", changes);
  180. [node removeObserverWithHandle:handle1];
  181. [node setValue:@84 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  182. [self waitUntil:^BOOL{ return done; }];
  183. done = NO;
  184. XCTAssertTrue(changes == 5, @"Saw 5 callback events %d", changes);
  185. [node removeObserverWithHandle:handle2];
  186. [node setValue:@168 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  187. [self waitUntil:^BOOL{ return done; }];
  188. done = NO;
  189. XCTAssertTrue(changes == 6, @"Saw 6 callback events %d", changes);
  190. [node removeObserverWithHandle:handle3];
  191. [node setValue:@376 withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  192. [self waitUntil:^BOOL{ return done; }];
  193. done = NO;
  194. XCTAssertTrue(changes == 6, @"Saw 6 callback events %d", changes);
  195. NSLog(@"callbacks: %d", changes);
  196. }
  197. - (void) testUnregisteringTheSameCallbackTooManyTimesDoesNothing {
  198. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  199. fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) { };
  200. FIRDatabaseHandle handle1 = [node observeEventType:FIRDataEventTypeValue withBlock:cb];
  201. [node removeObserverWithHandle:handle1];
  202. [node removeObserverWithHandle:handle1];
  203. XCTAssertTrue(YES, @"Properly reached end of test without throwing errors.");
  204. }
  205. - (void) testOnceValueFiresExactlyOnce {
  206. FIRDatabaseReference * path = [FTestHelpers getRandomNode];
  207. __block BOOL firstCall = YES;
  208. [path observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  209. XCTAssertTrue(firstCall, @"Properly saw first call");
  210. firstCall = NO;
  211. XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw node value");
  212. }];
  213. [path setValue:@42];
  214. [path setValue:@84];
  215. __block BOOL done = NO;
  216. [path setValue:nil withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  217. [self waitUntil:^BOOL{ return done; }];
  218. }
  219. - (void) testOnceChildAddedFiresExaclyOnce {
  220. __block int badCount = 0;
  221. // for(int i = 0; i < 100; i++) {
  222. FIRDatabaseReference * path = [FTestHelpers getRandomNode];
  223. __block BOOL firstCall = YES;
  224. __block BOOL done = NO;
  225. [path observeSingleEventOfType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  226. XCTAssertTrue(firstCall, @"Properly saw first call");
  227. firstCall = NO;
  228. XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw node value");
  229. XCTAssertEqualObjects(@"foo", [snapshot key], @"Properly saw the first node");
  230. if (![[snapshot value] isEqual:@42]) {
  231. exit(-1);
  232. badCount = badCount + 1;
  233. }
  234. done = YES;
  235. }];
  236. [[path child:@"foo"] setValue:@42];
  237. [[path child:@"bar"] setValue:@84]; // XXX FIXME sometimes this event fires first
  238. [[path child:@"foo"] setValue:@168];
  239. // [path setValue:nil withCompletionBlock:^(BOOL status) { done = YES; }];
  240. [self waitUntil:^BOOL{ return done; }];
  241. // }
  242. NSLog(@"BADCOUNT: %d", badCount);
  243. }
  244. - (void) testOnceValueFiresExacltyOnceEvenIfThereIsASetInsideCallback {
  245. FIRDatabaseReference * path = [FTestHelpers getRandomNode];
  246. __block BOOL firstCall = YES;
  247. __block BOOL done = NO;
  248. [path observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  249. XCTAssertTrue(firstCall, @"Properly saw first call");
  250. if (firstCall) {
  251. firstCall = NO;
  252. XCTAssertEqualObjects(@42, [snapshot value], @"Properly saw node value");
  253. [path setValue:@43];
  254. done = YES;
  255. }
  256. else {
  257. XCTFail(@"Callback got called more than once.");
  258. }
  259. }];
  260. [path setValue:@42];
  261. [path setValue:@84];
  262. [self waitUntil:^BOOL{ return done; }];
  263. }
  264. - (void) testOnceChildAddedFiresOnceEvenWithCompoundObject {
  265. FIRDatabaseReference * path = [FTestHelpers getRandomNode];
  266. __block BOOL firstCall = YES;
  267. [path observeSingleEventOfType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
  268. XCTAssertTrue(firstCall, @"Properly saw first call");
  269. firstCall = NO;
  270. XCTAssertEqualObjects(@84, [snapshot value], @"Properly saw node value");
  271. XCTAssertEqualObjects(@"bar", [snapshot key], @"Properly saw the first node");
  272. }];
  273. [path setValue:@{@"foo": @42, @"bar": @84}];
  274. __block BOOL done = NO;
  275. [path setValue:nil withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) { done = YES; }];
  276. [self waitUntil:^BOOL{ return done; }];
  277. }
  278. - (void) testOnEmptyChildFires {
  279. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  280. __block BOOL done = NO;
  281. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  282. }];
  283. [[node child:@"test"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  284. XCTAssertTrue([[snapshot value] isEqual:[NSNull null]], @"Properly saw nil child node");
  285. done = YES;
  286. }];
  287. [self waitUntil:^BOOL{ return done; }];
  288. }
  289. - (void) testOnEmptyChildEvenAfterParentIsSynched {
  290. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  291. __block BOOL parentDone = NO;
  292. __block BOOL done = NO;
  293. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  294. parentDone = YES;
  295. }];
  296. [self waitUntil:^BOOL{
  297. return parentDone;
  298. }];
  299. [[node child:@"test"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  300. XCTAssertTrue([[snapshot value] isEqual:[NSNull null]], @"Child is properly nil");
  301. done = YES;
  302. }];
  303. // 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
  304. [self waitUntil:^BOOL{
  305. return done;
  306. }];
  307. XCTAssertTrue(done, @"Done fired.");
  308. }
  309. - (void) testEventsAreRaisedChildRemovedChildAddedChildMoved {
  310. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  311. NSMutableArray* events = [[NSMutableArray alloc] init];
  312. [node observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snap) {
  313. [events addObject:[NSString stringWithFormat:@"added %@", [snap key]]];
  314. }];
  315. [node observeEventType:FIRDataEventTypeChildRemoved withBlock:^(FIRDataSnapshot *snap) {
  316. [events addObject:[NSString stringWithFormat:@"removed %@", [snap key]]];
  317. }];
  318. [node observeEventType:FIRDataEventTypeChildMoved withBlock:^(FIRDataSnapshot *snap) {
  319. [events addObject:[NSString stringWithFormat:@"moved %@", [snap key]]];
  320. }];
  321. __block BOOL done = NO;
  322. [node setValue:@{
  323. @"a": @{@".value": @1, @".priority": @0 },
  324. @"b": @{@".value": @1, @".priority": @1 },
  325. @"c": @{@".value": @1, @".priority": @2 },
  326. @"d": @{@".value": @1, @".priority": @3 },
  327. @"e": @{@".value": @1, @".priority": @4 },
  328. @"f": @{@".value": @1, @".priority": @5 },
  329. } withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  330. done = YES;
  331. }];
  332. [self waitUntil:^BOOL{
  333. return done;
  334. }];
  335. [events removeAllObjects];
  336. done = NO;
  337. [node setValue:@{
  338. @"a": @{@".value": @1, @".priority": @5 },
  339. @"aa": @{@".value": @1, @".priority": @0 },
  340. @"b": @{@".value": @1, @".priority": @1 },
  341. @"bb": @{@".value": @1, @".priority": @2 },
  342. @"d": @{@".value": @1, @".priority": @3 },
  343. @"e": @{@".value": @1, @".priority": @6 },
  344. }
  345. withCompletionBlock:^(NSError* error, FIRDatabaseReference * ref) {
  346. done = YES;
  347. }
  348. ];
  349. [self waitUntil:^BOOL{
  350. return done;
  351. }];
  352. XCTAssertEqualObjects(@"removed c, removed f, added aa, added bb, moved a, moved e", [events componentsJoinedByString:@", "], @"Got expected results");
  353. }
  354. - (void) testIntegerToDoubleConversions {
  355. FIRDatabaseReference * node = [FTestHelpers getRandomNode];
  356. NSMutableArray<NSString *>* events = [[NSMutableArray alloc] init];
  357. [node observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snap) {
  358. [events addObject:[NSString stringWithFormat:@"value %@", [snap value]]];
  359. }];
  360. for(NSNumber *number in @[@1, @1.0, @1, @1.1]) {
  361. [self waitForCompletionOf:node setValue:number];
  362. }
  363. XCTAssertEqualObjects(@"value 1, value 1.1", [events componentsJoinedByString:@", "],
  364. @"Got expected results");
  365. }
  366. - (void) testEventsAreRaisedProperlyWithOnQueryLimits {
  367. // xxx impl query
  368. }
  369. @end