FEventTests.m 19 KB

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